opal-security 3.1.1-beta.e5e99da → 3.1.1-beta.e92fdf8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -18
- package/lib/commands/request/create.js +7 -7
- package/lib/commands/request/get.d.ts +2 -0
- package/lib/commands/request/get.js +28 -3
- package/lib/commands/request/list.d.ts +8 -1
- package/lib/commands/request/list.js +113 -6
- package/lib/graphql/gql.d.ts +21 -6
- package/lib/graphql/gql.js +6 -3
- package/lib/graphql/graphql.d.ts +210 -94
- package/lib/graphql/graphql.js +1295 -347
- package/lib/lib/requests.d.ts +8 -4
- package/lib/lib/requests.js +499 -127
- package/lib/utils/displays.d.ts +8 -3
- package/lib/utils/displays.js +190 -42
- package/oclif.manifest.json +81 -33
- package/package.json +4 -1
package/lib/lib/requests.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.initEmptyRequestMetadata = initEmptyRequestMetadata;
|
|
4
4
|
exports.selectRequestableItems = selectRequestableItems;
|
|
5
5
|
exports.chooseAssets = chooseAssets;
|
|
6
6
|
exports.chooseRoles = chooseRoles;
|
|
@@ -9,10 +9,13 @@ exports.setRequestDefaults = setRequestDefaults;
|
|
|
9
9
|
exports.promptForReason = promptForReason;
|
|
10
10
|
exports.promptForExpiration = promptForExpiration;
|
|
11
11
|
exports.submitFinalRequest = submitFinalRequest;
|
|
12
|
+
const chalk_1 = require("chalk");
|
|
12
13
|
const inquirer = require("inquirer");
|
|
13
14
|
const graphql_1 = require("../graphql");
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
const displays_1 = require("../utils/displays");
|
|
16
|
+
const config_1 = require("./config");
|
|
17
|
+
const { AutoComplete, Select, prompt, Form } = require("enquirer");
|
|
18
|
+
function initEmptyRequestMetadata() {
|
|
16
19
|
// Initialize with empty defaults
|
|
17
20
|
const requestDefaults = {
|
|
18
21
|
durationOptions: [],
|
|
@@ -28,6 +31,9 @@ function createEmptyRequestMetadata() {
|
|
|
28
31
|
return {
|
|
29
32
|
requestMap,
|
|
30
33
|
requestDefaults,
|
|
34
|
+
durationLabel: "",
|
|
35
|
+
durationInMinutes: 0,
|
|
36
|
+
reason: "",
|
|
31
37
|
};
|
|
32
38
|
}
|
|
33
39
|
// Queries and Mutations
|
|
@@ -73,18 +79,22 @@ async function queryRequestableApps(cmd, client, input) {
|
|
|
73
79
|
});
|
|
74
80
|
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
81
|
let type = undefined;
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
switch (edge.node.__typename) {
|
|
83
|
+
case "Resource":
|
|
84
|
+
type = edge.node.resourceType;
|
|
85
|
+
break;
|
|
86
|
+
case "Connection":
|
|
87
|
+
type = edge.node.connectionType;
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
type = edge.node.__typename;
|
|
78
91
|
}
|
|
79
|
-
if (edge.node.__typename === "Connection") {
|
|
80
|
-
type = edge.node.connectionType;
|
|
81
|
-
}
|
|
82
|
-
const label = `${edge.node.displayName} (${type})`;
|
|
83
92
|
return {
|
|
84
|
-
|
|
93
|
+
message: `${edge.node.displayName} [${type}]`,
|
|
85
94
|
value: {
|
|
86
95
|
id: edge.node.id,
|
|
87
|
-
name:
|
|
96
|
+
name: edge.node.displayName,
|
|
97
|
+
toString: () => edge.node.displayName,
|
|
88
98
|
},
|
|
89
99
|
};
|
|
90
100
|
});
|
|
@@ -147,16 +157,16 @@ async function queryRequestableAssets(cmd, client, appId, input) {
|
|
|
147
157
|
switch (resp.data.app.__typename) {
|
|
148
158
|
case "App":
|
|
149
159
|
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;
|
|
160
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
151
161
|
const name = ((_a = item.resource) === null || _a === void 0 ? void 0 : _a.name) || ((_b = item.group) === null || _b === void 0 ? void 0 : _b.name);
|
|
152
162
|
const id = ((_c = item.resource) === null || _c === void 0 ? void 0 : _c.id) || ((_d = item.group) === null || _d === void 0 ? void 0 : _d.id);
|
|
153
163
|
const type = ((_e = item.resource) === null || _e === void 0 ? void 0 : _e.__typename) || ((_f = item.group) === null || _f === void 0 ? void 0 : _f.__typename);
|
|
154
|
-
const label = `${name} (${type})`;
|
|
155
164
|
return {
|
|
156
|
-
|
|
165
|
+
message: `${name} [${type}]`,
|
|
157
166
|
value: {
|
|
158
|
-
name:
|
|
159
|
-
id: id,
|
|
167
|
+
name: name || "",
|
|
168
|
+
id: id || "",
|
|
169
|
+
type: ((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename) || "",
|
|
160
170
|
},
|
|
161
171
|
};
|
|
162
172
|
});
|
|
@@ -182,7 +192,6 @@ const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
|
182
192
|
__typename
|
|
183
193
|
... on ResourceAccessLevelsResult {
|
|
184
194
|
accessLevels {
|
|
185
|
-
__typename
|
|
186
195
|
... on ResourceAccessLevel {
|
|
187
196
|
accessLevelName
|
|
188
197
|
accessLevelRemoteId
|
|
@@ -195,34 +204,82 @@ const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
|
195
204
|
}
|
|
196
205
|
}
|
|
197
206
|
`);
|
|
198
|
-
|
|
199
|
-
|
|
207
|
+
const GROUP_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
208
|
+
query GroupAccessLevels($groupId: GroupId!) {
|
|
209
|
+
groupAccessLevels(
|
|
210
|
+
input: { groupId: $groupId }
|
|
211
|
+
) {
|
|
212
|
+
... on GroupAccessLevelsResult {
|
|
213
|
+
groupId
|
|
214
|
+
accessLevels {
|
|
215
|
+
... on GroupAccessLevel {
|
|
216
|
+
accessLevelName
|
|
217
|
+
accessLevelRemoteId
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
`);
|
|
224
|
+
async function queryAssetRoles(cmd, client, assetType, assetId) {
|
|
225
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
200
226
|
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
|
-
};
|
|
227
|
+
switch (assetType) {
|
|
228
|
+
case "Resource": {
|
|
229
|
+
const resp = await client.query({
|
|
230
|
+
query: RESOURCE_ROLES_QUERY,
|
|
231
|
+
variables: {
|
|
232
|
+
resourceId: assetId,
|
|
233
|
+
},
|
|
234
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
220
235
|
});
|
|
221
|
-
|
|
222
|
-
x
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
236
|
+
// no fall through doesn't consider process.exit();
|
|
237
|
+
let x;
|
|
238
|
+
switch (resp.data.accessLevels.__typename) {
|
|
239
|
+
case "ResourceAccessLevelsResult":
|
|
240
|
+
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) => {
|
|
241
|
+
return {
|
|
242
|
+
message: role.accessLevelName || "",
|
|
243
|
+
value: {
|
|
244
|
+
name: role.accessLevelName || "",
|
|
245
|
+
id: role.accessLevelRemoteId || "",
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
case "ResourceNotFoundError":
|
|
250
|
+
x = cmd.error((_e = (_d = resp.data) === null || _d === void 0 ? void 0 : _d.accessLevels) === null || _e === void 0 ? void 0 : _e.message);
|
|
251
|
+
break;
|
|
252
|
+
default:
|
|
253
|
+
cmd.error(resp.error || "Unknown error occurred.");
|
|
254
|
+
}
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
case "Group": {
|
|
258
|
+
const resp = await client.query({
|
|
259
|
+
query: GROUP_ROLES_QUERY,
|
|
260
|
+
variables: {
|
|
261
|
+
groupId: assetId,
|
|
262
|
+
},
|
|
263
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
264
|
+
});
|
|
265
|
+
// no fall through doesn't consider process.exit();
|
|
266
|
+
let x;
|
|
267
|
+
switch (resp.data.groupAccessLevels.__typename) {
|
|
268
|
+
case "GroupAccessLevelsResult":
|
|
269
|
+
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) => {
|
|
270
|
+
return {
|
|
271
|
+
message: role.accessLevelName,
|
|
272
|
+
value: {
|
|
273
|
+
name: role.accessLevelName,
|
|
274
|
+
id: role.accessLevelRemoteId,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
default:
|
|
279
|
+
x = cmd.error(resp.error || "Unknown error occurred.");
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
226
283
|
}
|
|
227
284
|
}
|
|
228
285
|
catch (error) {
|
|
@@ -241,16 +298,18 @@ const REQUEST_DEFAULTS_QUERY = (0, graphql_1.graphql)(`
|
|
|
241
298
|
requestedGroups: $requestedGroups,
|
|
242
299
|
}
|
|
243
300
|
) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
301
|
+
... on RequestDefaults {
|
|
302
|
+
durationOptions {
|
|
303
|
+
durationInMinutes
|
|
304
|
+
label
|
|
305
|
+
}
|
|
306
|
+
recommendedDurationInMinutes
|
|
307
|
+
defaultDurationInMinutes
|
|
308
|
+
maxDurationInMinutes
|
|
309
|
+
requireSupportTicket
|
|
310
|
+
reasonOptional
|
|
311
|
+
requesterIsAdmin
|
|
247
312
|
}
|
|
248
|
-
recommendedDurationInMinutes
|
|
249
|
-
defaultDurationInMinutes
|
|
250
|
-
maxDurationInMinutes
|
|
251
|
-
requireSupportTicket
|
|
252
|
-
reasonOptional
|
|
253
|
-
requesterIsAdmin
|
|
254
313
|
}
|
|
255
314
|
}`);
|
|
256
315
|
async function queryRequestDefaults(cmd, client, requestedResources, requestedGroups) {
|
|
@@ -271,20 +330,175 @@ async function queryRequestDefaults(cmd, client, requestedResources, requestedGr
|
|
|
271
330
|
}
|
|
272
331
|
}
|
|
273
332
|
}
|
|
333
|
+
const CREATE_REQUEST_MUTATION = (0, graphql_1.graphql)(`
|
|
334
|
+
mutation CreateRequest(
|
|
335
|
+
$requestedResources: [RequestedResourceInput!]!
|
|
336
|
+
$requestedGroups: [RequestedGroupInput!]!
|
|
337
|
+
$reason: String!
|
|
338
|
+
$durationInMinutes: Int
|
|
339
|
+
) {
|
|
340
|
+
createRequest(
|
|
341
|
+
input: {
|
|
342
|
+
requestedResources: $requestedResources
|
|
343
|
+
requestedGroups: $requestedGroups
|
|
344
|
+
reason: $reason
|
|
345
|
+
durationInMinutes: $durationInMinutes
|
|
346
|
+
}
|
|
347
|
+
) {
|
|
348
|
+
... on CreateRequestResult {
|
|
349
|
+
request {
|
|
350
|
+
id
|
|
351
|
+
status
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
... on RequestDurationTooLargeError {
|
|
355
|
+
message
|
|
356
|
+
}
|
|
357
|
+
... on RequestRequiresUserAuthTokenForConnectionError {
|
|
358
|
+
message
|
|
359
|
+
}
|
|
360
|
+
... on NoReviewersSetForOwnerError {
|
|
361
|
+
message
|
|
362
|
+
ownerId
|
|
363
|
+
}
|
|
364
|
+
... on NoReviewersSetForResourceError {
|
|
365
|
+
message
|
|
366
|
+
resourceId
|
|
367
|
+
}
|
|
368
|
+
... on NoReviewersSetForGroupError {
|
|
369
|
+
message
|
|
370
|
+
groupId
|
|
371
|
+
}
|
|
372
|
+
... on NoManagerSetForRequestingUserError {
|
|
373
|
+
message
|
|
374
|
+
}
|
|
375
|
+
... on MfaInvalidError {
|
|
376
|
+
message
|
|
377
|
+
}
|
|
378
|
+
... on BulkRequestTooLargeError {
|
|
379
|
+
message
|
|
380
|
+
}
|
|
381
|
+
... on ItemCannotBeRequestedError {
|
|
382
|
+
message
|
|
383
|
+
}
|
|
384
|
+
... on UserCannotRequestAccessForTargetGroupError {
|
|
385
|
+
message
|
|
386
|
+
groupId
|
|
387
|
+
userId
|
|
388
|
+
}
|
|
389
|
+
... on GroupNestingNotAllowedError {
|
|
390
|
+
message
|
|
391
|
+
fromGroupId
|
|
392
|
+
toGroupId
|
|
393
|
+
}
|
|
394
|
+
... on TargetUserHasNestedAccessError {
|
|
395
|
+
message
|
|
396
|
+
groupIds
|
|
397
|
+
}
|
|
398
|
+
... on RequestReasonMissingError {
|
|
399
|
+
message
|
|
400
|
+
}
|
|
401
|
+
... on RequestFieldValueMissingError {
|
|
402
|
+
message
|
|
403
|
+
fieldName
|
|
404
|
+
}
|
|
405
|
+
... on LinkedGroupNotRequestableError {
|
|
406
|
+
message
|
|
407
|
+
sourceGroupId
|
|
408
|
+
groupBindingId
|
|
409
|
+
}
|
|
410
|
+
... on RequestReasonBelowMinLengthError {
|
|
411
|
+
message
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`);
|
|
417
|
+
async function createRequest(cmd, client, requestedResources, requestedGroups, reason, durationInMinutes) {
|
|
418
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
419
|
+
try {
|
|
420
|
+
const resp = await client.mutate({
|
|
421
|
+
mutation: CREATE_REQUEST_MUTATION,
|
|
422
|
+
variables: {
|
|
423
|
+
requestedResources: requestedResources,
|
|
424
|
+
requestedGroups: requestedGroups,
|
|
425
|
+
reason: reason,
|
|
426
|
+
durationInMinutes: durationInMinutes,
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.createRequest.__typename) {
|
|
430
|
+
case "CreateRequestResult":
|
|
431
|
+
return (_b = resp.data) === null || _b === void 0 ? void 0 : _b.createRequest.request;
|
|
432
|
+
case "RequestDurationTooLargeError":
|
|
433
|
+
cmd.log((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
|
|
434
|
+
break;
|
|
435
|
+
case "RequestRequiresUserAuthTokenForConnectionError":
|
|
436
|
+
cmd.log((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
|
|
437
|
+
break;
|
|
438
|
+
case "NoReviewersSetForOwnerError":
|
|
439
|
+
cmd.log((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
|
|
440
|
+
break;
|
|
441
|
+
case "NoReviewersSetForResourceError":
|
|
442
|
+
cmd.log((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
|
|
443
|
+
break;
|
|
444
|
+
case "NoReviewersSetForGroupError":
|
|
445
|
+
cmd.log((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
|
|
446
|
+
break;
|
|
447
|
+
case "NoManagerSetForRequestingUserError":
|
|
448
|
+
cmd.log((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
|
|
449
|
+
break;
|
|
450
|
+
case "MfaInvalidError":
|
|
451
|
+
cmd.log((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
|
|
452
|
+
break;
|
|
453
|
+
case "BulkRequestTooLargeError":
|
|
454
|
+
cmd.log((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
|
|
455
|
+
break;
|
|
456
|
+
case "ItemCannotBeRequestedError":
|
|
457
|
+
cmd.log((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
|
|
458
|
+
break;
|
|
459
|
+
case "UserCannotRequestAccessForTargetGroupError":
|
|
460
|
+
cmd.log((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
|
|
461
|
+
break;
|
|
462
|
+
case "GroupNestingNotAllowedError":
|
|
463
|
+
cmd.log((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
|
|
464
|
+
break;
|
|
465
|
+
case "TargetUserHasNestedAccessError":
|
|
466
|
+
cmd.log((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
|
|
467
|
+
break;
|
|
468
|
+
case "RequestReasonMissingError":
|
|
469
|
+
cmd.log((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
|
|
470
|
+
break;
|
|
471
|
+
case "RequestFieldValueMissingError":
|
|
472
|
+
cmd.log((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
|
|
473
|
+
break;
|
|
474
|
+
case "LinkedGroupNotRequestableError":
|
|
475
|
+
cmd.log((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
|
|
476
|
+
break;
|
|
477
|
+
case "RequestReasonBelowMinLengthError":
|
|
478
|
+
cmd.log((_t = resp.data) === null || _t === void 0 ? void 0 : _t.createRequest.message);
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
if (error instanceof Error || typeof error === "string") {
|
|
484
|
+
cmd.error(error);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
274
488
|
// Helper functions
|
|
275
489
|
async function selectRequestableItems(cmd, client, requestMap) {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
pageSize: 15,
|
|
490
|
+
const initialChoices = (await queryRequestableApps(cmd, client, "")) || [];
|
|
491
|
+
const appPrompt = new AutoComplete({
|
|
492
|
+
name: "App",
|
|
493
|
+
message: "Select an app:",
|
|
494
|
+
limit: 15,
|
|
495
|
+
choices: initialChoices,
|
|
496
|
+
async suggest(input) {
|
|
497
|
+
const filteredChoices = await queryRequestableApps(cmd, client, input || "");
|
|
498
|
+
return filteredChoices || initialChoices;
|
|
286
499
|
},
|
|
287
|
-
|
|
500
|
+
});
|
|
501
|
+
const App = await appPrompt.run();
|
|
288
502
|
// Set the app in the requestMap and call choose assets step
|
|
289
503
|
if (!(App.id in requestMap)) {
|
|
290
504
|
requestMap[App.id] = {
|
|
@@ -295,13 +509,16 @@ async function selectRequestableItems(cmd, client, requestMap) {
|
|
|
295
509
|
await chooseAssets(cmd, client, App.id, requestMap);
|
|
296
510
|
}
|
|
297
511
|
async function chooseAssets(cmd, client, appId, requestMap) {
|
|
298
|
-
|
|
299
|
-
const
|
|
512
|
+
const initialChoices = (await queryRequestableAssets(cmd, client, appId, "")) || [];
|
|
513
|
+
const assetPrompt = new AutoComplete({
|
|
300
514
|
name: "Assets",
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
choices
|
|
515
|
+
message: "Select one or more assets:",
|
|
516
|
+
limit: 15,
|
|
517
|
+
multiple: true,
|
|
518
|
+
async choices(input) {
|
|
519
|
+
const filteredChoices = await queryRequestableAssets(cmd, client, appId, input);
|
|
520
|
+
return filteredChoices || initialChoices;
|
|
521
|
+
},
|
|
305
522
|
validate: (answer) => {
|
|
306
523
|
if (answer.length < 1) {
|
|
307
524
|
return "You must select at least one item.";
|
|
@@ -309,14 +526,16 @@ async function chooseAssets(cmd, client, appId, requestMap) {
|
|
|
309
526
|
return true;
|
|
310
527
|
},
|
|
311
528
|
});
|
|
529
|
+
const Assets = await assetPrompt.run();
|
|
312
530
|
const entry = requestMap[appId];
|
|
313
531
|
for (const asset of Assets) {
|
|
314
532
|
if (entry === undefined) {
|
|
315
|
-
throw new Error(`
|
|
533
|
+
throw new Error(`Error formatting app ${appId} in request`);
|
|
316
534
|
}
|
|
317
535
|
if (!(asset.id in entry.assets)) {
|
|
318
536
|
entry.assets[asset.id] = {
|
|
319
537
|
assetName: asset.name,
|
|
538
|
+
type: asset.type,
|
|
320
539
|
roles: {},
|
|
321
540
|
};
|
|
322
541
|
}
|
|
@@ -325,29 +544,31 @@ async function chooseAssets(cmd, client, appId, requestMap) {
|
|
|
325
544
|
}
|
|
326
545
|
async function chooseRoles(cmd, client, appId, assetId, requestMap) {
|
|
327
546
|
var _a;
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
547
|
+
const entry = requestMap[appId];
|
|
548
|
+
const assetEntry = entry === null || entry === void 0 ? void 0 : entry.assets[assetId];
|
|
549
|
+
if (entry === undefined || assetEntry === undefined) {
|
|
550
|
+
throw new Error(`App ${appId} or Asset ${assetId} not found in requestMap`);
|
|
551
|
+
}
|
|
552
|
+
const assetRoles = (_a = (await queryAssetRoles(cmd, client, assetEntry.type, assetId))) !== null && _a !== void 0 ? _a : [];
|
|
553
|
+
if (assetRoles !== undefined &&
|
|
554
|
+
(assetRoles.length === 0 ||
|
|
555
|
+
(assetRoles.length === 1 && assetRoles[0].value.name === ""))) {
|
|
332
556
|
return;
|
|
333
557
|
}
|
|
334
|
-
const
|
|
335
|
-
name: "
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
558
|
+
const rolePrompt = new AutoComplete({
|
|
559
|
+
name: "Roles",
|
|
560
|
+
message: `Select one or more roles for ${assetEntry.assetName}:`,
|
|
561
|
+
limit: 15,
|
|
562
|
+
multiple: true,
|
|
563
|
+
choices: assetRoles,
|
|
339
564
|
validate: (answer) => {
|
|
340
|
-
if (
|
|
341
|
-
return "You must select at least one
|
|
565
|
+
if (answer.length < 1) {
|
|
566
|
+
return "You must select at least one item.";
|
|
342
567
|
}
|
|
343
568
|
return true;
|
|
344
569
|
},
|
|
345
570
|
});
|
|
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
|
-
}
|
|
571
|
+
const roles = await rolePrompt.run();
|
|
351
572
|
if (!assetEntry.roles) {
|
|
352
573
|
assetEntry.roles = {};
|
|
353
574
|
}
|
|
@@ -360,14 +581,12 @@ async function chooseRoles(cmd, client, appId, assetId, requestMap) {
|
|
|
360
581
|
async function doneSelectingAssets() {
|
|
361
582
|
const submitMessage = "✅ Yes, proceed with request";
|
|
362
583
|
const addMoreMessage = "❌ No, add more items";
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
},
|
|
370
|
-
]);
|
|
584
|
+
const prompt = new Select({
|
|
585
|
+
name: "submitOrAdd",
|
|
586
|
+
message: "Is this all you want to request?",
|
|
587
|
+
choices: [submitMessage, addMoreMessage],
|
|
588
|
+
});
|
|
589
|
+
const submitOrAdd = await prompt.run();
|
|
371
590
|
return submitOrAdd === submitMessage;
|
|
372
591
|
}
|
|
373
592
|
async function setRequestDefaults(cmd, client, metadata) {
|
|
@@ -377,18 +596,34 @@ async function setRequestDefaults(cmd, client, metadata) {
|
|
|
377
596
|
for (const appNode of Object.values(requestMap)) {
|
|
378
597
|
for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
379
598
|
if (assetNode.roles !== undefined) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
599
|
+
const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
|
|
600
|
+
return roleId;
|
|
601
|
+
});
|
|
602
|
+
const roleIds = mappedRoles.length ? mappedRoles : [""];
|
|
603
|
+
for (const roleId of roleIds) {
|
|
604
|
+
switch (assetNode.type) {
|
|
605
|
+
case "Resource": {
|
|
606
|
+
requestedResources.push({
|
|
607
|
+
resourceId: assetId,
|
|
608
|
+
accessLevelRemoteId: roleId,
|
|
609
|
+
});
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
case "Group": {
|
|
613
|
+
requestedGroups.push({
|
|
614
|
+
groupId: assetId,
|
|
615
|
+
accessLevelRemoteId: roleId,
|
|
616
|
+
});
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
385
620
|
}
|
|
386
621
|
}
|
|
387
622
|
}
|
|
388
623
|
}
|
|
389
624
|
try {
|
|
390
625
|
const requestDefaults = await queryRequestDefaults(cmd, client, requestedResources, requestedGroups);
|
|
391
|
-
if (
|
|
626
|
+
if (requestDefaults !== undefined) {
|
|
392
627
|
metadata.requestDefaults.durationOptions =
|
|
393
628
|
requestDefaults.durationOptions;
|
|
394
629
|
metadata.requestDefaults.recommendedDurationInMinutes =
|
|
@@ -409,49 +644,133 @@ async function setRequestDefaults(cmd, client, metadata) {
|
|
|
409
644
|
}
|
|
410
645
|
}
|
|
411
646
|
async function promptForReason(metadata) {
|
|
412
|
-
|
|
647
|
+
const { reason } = await prompt([
|
|
413
648
|
{
|
|
414
649
|
name: "reason",
|
|
415
650
|
message: "I need access to this because...",
|
|
416
651
|
type: "input",
|
|
417
652
|
validate: (answer) => {
|
|
418
|
-
if (metadata.requestDefaults.reasonOptional && answer.length < 1) {
|
|
653
|
+
if (!metadata.requestDefaults.reasonOptional && answer.length < 1) {
|
|
419
654
|
return "A reason for requesting these assets is required.";
|
|
420
655
|
}
|
|
421
656
|
return true;
|
|
422
657
|
},
|
|
423
658
|
},
|
|
424
659
|
]);
|
|
660
|
+
metadata.reason = reason;
|
|
425
661
|
}
|
|
426
662
|
async function promptForExpiration(metadata) {
|
|
427
663
|
var _a, _b;
|
|
428
664
|
const durations = ((_b = (_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.durationOptions) === null || _b === void 0 ? void 0 : _b.map((option) => {
|
|
665
|
+
var _a;
|
|
666
|
+
let label = option.label;
|
|
667
|
+
if (option.durationInMinutes ===
|
|
668
|
+
((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes)) {
|
|
669
|
+
label = `${label} (MAX)`;
|
|
670
|
+
}
|
|
671
|
+
if (option.durationInMinutes ===
|
|
672
|
+
metadata.requestDefaults.recommendedDurationInMinutes) {
|
|
673
|
+
label = `${label} (RECOMMENDED)`;
|
|
674
|
+
}
|
|
429
675
|
return {
|
|
430
|
-
|
|
431
|
-
metadata.requestDefaults.recommendedDurationInMinutes
|
|
432
|
-
? `${option.label} (Recommended)`
|
|
433
|
-
: option.label,
|
|
676
|
+
message: label,
|
|
434
677
|
value: {
|
|
435
|
-
label:
|
|
678
|
+
label: label,
|
|
436
679
|
durationInMinutes: option.durationInMinutes,
|
|
680
|
+
toString: () => label,
|
|
437
681
|
},
|
|
438
682
|
};
|
|
439
683
|
})) || [];
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
684
|
+
// Sort durations by minutes
|
|
685
|
+
durations.sort((a, b) => a.value.durationInMinutes - b.value.durationInMinutes);
|
|
686
|
+
const expirationSelect = new AutoComplete({
|
|
687
|
+
name: "expiration",
|
|
688
|
+
message: "When should access expire?",
|
|
689
|
+
type: "list",
|
|
690
|
+
choices: durations,
|
|
691
|
+
pageSize: 15,
|
|
692
|
+
});
|
|
693
|
+
let selected = await expirationSelect.run();
|
|
694
|
+
switch (selected.label) {
|
|
695
|
+
case "Custom": {
|
|
696
|
+
selected = await setCustomDuration(metadata);
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
case "Permanent": {
|
|
700
|
+
selected.durationInMinutes = undefined;
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
metadata.durationInMinutes = selected.durationInMinutes;
|
|
705
|
+
metadata.durationLabel = selected.label;
|
|
706
|
+
}
|
|
707
|
+
function getDurationNumbers(duration) {
|
|
708
|
+
const d = +duration.days || 0;
|
|
709
|
+
const h = +duration.hours || 0;
|
|
710
|
+
const m = +duration.minutes || 0;
|
|
711
|
+
return { d, h, m };
|
|
712
|
+
}
|
|
713
|
+
function getDurationInMinutes(duration) {
|
|
714
|
+
const { d, h, m } = getDurationNumbers(duration);
|
|
715
|
+
const minutesInDay = 1440; // 24 hours * 60 minutes
|
|
716
|
+
const minutesInHour = 60;
|
|
717
|
+
return d * minutesInDay + h * minutesInHour + m;
|
|
718
|
+
}
|
|
719
|
+
function getDHMFromMinutes(minutes) {
|
|
720
|
+
const label = [];
|
|
721
|
+
const d = Math.floor(minutes / 1440);
|
|
722
|
+
if (d > 0) {
|
|
723
|
+
label.push(`${d}d`);
|
|
724
|
+
}
|
|
725
|
+
const remainingMinutes = minutes % 1440;
|
|
726
|
+
const h = Math.floor(remainingMinutes / 60);
|
|
727
|
+
if (h > 0) {
|
|
728
|
+
label.push(`${h}h`);
|
|
729
|
+
}
|
|
730
|
+
const m = remainingMinutes % 60;
|
|
731
|
+
if (m > 0) {
|
|
732
|
+
label.push(`${m}m`);
|
|
733
|
+
}
|
|
734
|
+
return label.join(" ");
|
|
735
|
+
}
|
|
736
|
+
async function setCustomDuration(metadata) {
|
|
737
|
+
const durationForm = new Form({
|
|
738
|
+
name: "user",
|
|
739
|
+
message: "Please set a custom access duration:",
|
|
740
|
+
choices: [
|
|
741
|
+
{ name: "days", message: "Days", initial: "0" },
|
|
742
|
+
{ name: "hours", message: "Hours", initial: "0" },
|
|
743
|
+
{ name: "minutes", message: "Minutes", initial: "0" },
|
|
744
|
+
],
|
|
745
|
+
validate: (answer) => {
|
|
746
|
+
var _a, _b, _c;
|
|
747
|
+
const { d, h, m } = getDurationNumbers(answer);
|
|
748
|
+
const durationInMinutes = getDurationInMinutes(answer);
|
|
749
|
+
if (d < 0 || h < 0 || m < 0 || d + h + m === 0 || (h > 23 && m > 59)) {
|
|
750
|
+
return "Please enter a valid duration.";
|
|
751
|
+
}
|
|
752
|
+
if (((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes) &&
|
|
753
|
+
durationInMinutes > ((_b = metadata.requestDefaults) === null || _b === void 0 ? void 0 : _b.maxDurationInMinutes)) {
|
|
754
|
+
const maxDHM = getDHMFromMinutes((_c = metadata.requestDefaults) === null || _c === void 0 ? void 0 : _c.maxDurationInMinutes);
|
|
755
|
+
return `The max duration for the selected assets is ${maxDHM}.`;
|
|
756
|
+
}
|
|
757
|
+
return true;
|
|
451
758
|
},
|
|
452
|
-
|
|
759
|
+
return: (answer) => {
|
|
760
|
+
return getDurationInMinutes(answer);
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
const durationResult = await durationForm.run();
|
|
764
|
+
const { d, h, m } = getDurationNumbers(durationResult);
|
|
765
|
+
const durationInMinutes = getDurationInMinutes(durationResult);
|
|
766
|
+
const durationLabel = getDHMFromMinutes(durationInMinutes);
|
|
767
|
+
return {
|
|
768
|
+
durationInMinutes: durationInMinutes,
|
|
769
|
+
label: durationLabel,
|
|
770
|
+
};
|
|
453
771
|
}
|
|
454
|
-
async function submitFinalRequest(cmd) {
|
|
772
|
+
async function submitFinalRequest(cmd, client, metadata) {
|
|
773
|
+
var _a, _b, _c, _d;
|
|
455
774
|
const submitMessage = "✅ Yes, submit request";
|
|
456
775
|
const cancelMessage = "❌ No, cancel request";
|
|
457
776
|
const { submit } = await inquirer.prompt([
|
|
@@ -462,12 +781,65 @@ async function submitFinalRequest(cmd) {
|
|
|
462
781
|
choices: [submitMessage, cancelMessage],
|
|
463
782
|
},
|
|
464
783
|
]);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
784
|
+
switch (submit) {
|
|
785
|
+
case submitMessage: {
|
|
786
|
+
// Build requested assets lists for the mutation
|
|
787
|
+
const requestedResources = [];
|
|
788
|
+
const requestedGroups = [];
|
|
789
|
+
for (const appNode of Object.values(metadata.requestMap)) {
|
|
790
|
+
for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
791
|
+
if (assetNode.roles !== undefined) {
|
|
792
|
+
const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
|
|
793
|
+
return roleId;
|
|
794
|
+
});
|
|
795
|
+
const roleIds = mappedRoles.length ? mappedRoles : [""];
|
|
796
|
+
for (const roleId of roleIds) {
|
|
797
|
+
switch (assetNode.type) {
|
|
798
|
+
case "Resource": {
|
|
799
|
+
requestedResources.push({
|
|
800
|
+
resourceId: assetId,
|
|
801
|
+
accessLevel: {
|
|
802
|
+
accessLevelName: ((_b = (_a = assetNode.roles) === null || _a === void 0 ? void 0 : _a[roleId]) === null || _b === void 0 ? void 0 : _b.roleName) || "",
|
|
803
|
+
accessLevelRemoteId: roleId,
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
case "Group": {
|
|
809
|
+
requestedGroups.push({
|
|
810
|
+
groupId: assetId,
|
|
811
|
+
accessLevel: {
|
|
812
|
+
accessLevelName: ((_d = (_c = assetNode.roles) === null || _c === void 0 ? void 0 : _c[roleId]) === null || _d === void 0 ? void 0 : _d.roleName) || "",
|
|
813
|
+
accessLevelRemoteId: roleId,
|
|
814
|
+
},
|
|
815
|
+
});
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const resp = await createRequest(cmd, client, requestedResources, requestedGroups, metadata.reason, metadata.durationInMinutes);
|
|
824
|
+
// Build link to request
|
|
825
|
+
const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
|
|
826
|
+
if (resp === null || resp === void 0 ? void 0 : resp.id) {
|
|
827
|
+
cmd.log("\n🎉 Your Access Request has been submitted!\n");
|
|
828
|
+
cmd.log(`${chalk_1.default.bold("ID: ")} ${chalk_1.default.cyan(resp === null || resp === void 0 ? void 0 : resp.id)}`);
|
|
829
|
+
if (resp === null || resp === void 0 ? void 0 : resp.status) {
|
|
830
|
+
cmd.log((0, displays_1.getStyledStatus)(resp === null || resp === void 0 ? void 0 : resp.status));
|
|
831
|
+
}
|
|
832
|
+
const requestLink = `${configData[config_1.urlKey]}/requests/sent/${resp === null || resp === void 0 ? void 0 : resp.id}`;
|
|
833
|
+
cmd.log(`${chalk_1.default.bold("Link:")} ${chalk_1.default.underline(requestLink)}\n`);
|
|
834
|
+
}
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
case cancelMessage: {
|
|
838
|
+
cmd.log("🚫 Access Request has been cancelled.");
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
default: {
|
|
842
|
+
cmd.error("Unknown error occurred.");
|
|
843
|
+
}
|
|
472
844
|
}
|
|
473
845
|
}
|