opal-security 3.2.1 → 3.2.3

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 (63) hide show
  1. package/README.md +28 -25
  2. package/lib/commands/login.js +18 -11
  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 +7 -58
  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 +1138 -383
  10. package/lib/graphql/graphql.js +1780 -1104
  11. package/lib/handler.d.ts +6 -6
  12. package/lib/handler.js +1 -1
  13. package/lib/labels.d.ts +3 -0
  14. package/lib/labels.js +40 -0
  15. package/lib/lib/apollo.d.ts +3 -3
  16. package/lib/lib/apollo.js +24 -47
  17. package/lib/lib/request/api/index.d.ts +6 -0
  18. package/lib/lib/request/api/index.js +20 -0
  19. package/lib/lib/request/api/mutations/create-request.d.ts +8 -0
  20. package/lib/lib/request/api/mutations/create-request.js +159 -0
  21. package/lib/lib/request/api/queries/apps.d.ts +4 -0
  22. package/lib/lib/request/api/queries/apps.js +73 -0
  23. package/lib/lib/request/api/queries/assets.d.ts +6 -0
  24. package/lib/lib/request/api/queries/assets.js +136 -0
  25. package/lib/lib/request/api/queries/request-defaults.d.ts +5 -0
  26. package/lib/lib/request/api/queries/request-defaults.js +52 -0
  27. package/lib/lib/request/api/queries/requests.d.ts +4 -0
  28. package/lib/lib/request/api/queries/requests.js +163 -0
  29. package/lib/lib/request/api/queries/roles.d.ts +5 -0
  30. package/lib/lib/request/api/queries/roles.js +239 -0
  31. package/lib/{utils → lib/request}/displays.d.ts +7 -5
  32. package/lib/{utils → lib/request}/displays.js +52 -30
  33. package/lib/lib/request/prompts/apps-prompt.d.ts +4 -0
  34. package/lib/lib/request/prompts/apps-prompt.js +35 -0
  35. package/lib/lib/request/prompts/asset-prompt.d.ts +5 -0
  36. package/lib/lib/request/prompts/asset-prompt.js +81 -0
  37. package/lib/lib/request/prompts/duration-prompt.d.ts +2 -0
  38. package/lib/lib/request/prompts/duration-prompt.js +125 -0
  39. package/lib/lib/request/prompts/index.d.ts +8 -0
  40. package/lib/lib/request/prompts/index.js +20 -0
  41. package/lib/lib/request/prompts/reason-prompt.d.ts +2 -0
  42. package/lib/lib/request/prompts/reason-prompt.js +20 -0
  43. package/lib/lib/request/prompts/role-prompt.d.ts +4 -0
  44. package/lib/lib/request/prompts/role-prompt.js +44 -0
  45. package/lib/lib/request/prompts/validate-prompt.d.ts +4 -0
  46. package/lib/lib/request/prompts/validate-prompt.js +29 -0
  47. package/lib/lib/request/request-utils.d.ts +14 -0
  48. package/lib/lib/request/request-utils.js +468 -0
  49. package/lib/lib/request/types.d.ts +55 -0
  50. package/lib/lib/request/types.js +15 -0
  51. package/lib/lib/resources.d.ts +1 -1
  52. package/lib/lib/sessions.d.ts +1 -1
  53. package/lib/lib/sessions.js +3 -2
  54. package/lib/lib/util.d.ts +1 -0
  55. package/lib/lib/util.js +16 -0
  56. package/lib/types.d.ts +19 -3
  57. package/lib/types.js +18 -2
  58. package/oclif.manifest.json +54 -38
  59. package/package.json +4 -3
  60. package/lib/lib/requests.d.ts +0 -54
  61. package/lib/lib/requests.js +0 -1160
  62. package/lib/utils/utils.d.ts +0 -1
  63. package/lib/utils/utils.js +0 -18
@@ -0,0 +1,468 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initEmptyRequestMetadata = initEmptyRequestMetadata;
4
+ exports.setRequestDefaults = setRequestDefaults;
5
+ exports.submitFinalRequest = submitFinalRequest;
6
+ exports.getRequestLink = getRequestLink;
7
+ exports.generateRequestLink = generateRequestLink;
8
+ exports.bypassRequestSelection = bypassRequestSelection;
9
+ exports.bypassDuration = bypassDuration;
10
+ exports.getRequestMessageFromCode = getRequestMessageFromCode;
11
+ exports.duplicateRequestTemplate = duplicateRequestTemplate;
12
+ exports.copyBundleAssets = copyBundleAssets;
13
+ const chalk_1 = require("chalk");
14
+ const graphql_1 = require("../../graphql/graphql");
15
+ const labels_1 = require("../../labels");
16
+ const config_1 = require("../../lib/config");
17
+ const api_1 = require("./api");
18
+ const requests_1 = require("./api/queries/requests");
19
+ const displays_1 = require("./displays");
20
+ const types_1 = require("./types");
21
+ /*
22
+ Init Request Metadata
23
+ This function initializes the request metadata with empty defaults and an empty request map.
24
+ */
25
+ function initEmptyRequestMetadata() {
26
+ // Initialize with empty defaults
27
+ const requestDefaults = {
28
+ durationOptions: [],
29
+ recommendedDurationInMinutes: undefined,
30
+ defaultDurationInMinutes: undefined,
31
+ maxDurationInMinutes: undefined,
32
+ requireSupportTicket: false,
33
+ reasonOptional: false,
34
+ requesterIsAdmin: false,
35
+ };
36
+ // Initialize with empty map
37
+ const requestMap = {};
38
+ return {
39
+ requestMap,
40
+ requestDefaults,
41
+ durationLabel: "",
42
+ durationInMinutes: 0,
43
+ reason: "",
44
+ };
45
+ }
46
+ /*
47
+ After setting up the request map, this function fetches the request defaults
48
+ from the server based on the requested resources and groups.
49
+ It updates the metadata with the fetched defaults.
50
+ */
51
+ async function setRequestDefaults(cmd, client, metadata) {
52
+ var _a;
53
+ const requestMap = metadata.requestMap;
54
+ const requestedResources = [];
55
+ const requestedGroups = [];
56
+ for (const appNode of Object.values(requestMap)) {
57
+ for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
58
+ if (assetNode.roles !== undefined) {
59
+ const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
60
+ return roleId;
61
+ });
62
+ const roleIds = mappedRoles.length ? mappedRoles : [""];
63
+ for (const roleId of roleIds) {
64
+ switch (assetNode.type) {
65
+ case graphql_1.EntityType.Resource: {
66
+ requestedResources.push({
67
+ resourceId: assetId,
68
+ accessLevelRemoteId: roleId,
69
+ });
70
+ break;
71
+ }
72
+ case graphql_1.EntityType.Group: {
73
+ requestedGroups.push({
74
+ groupId: assetId,
75
+ accessLevelRemoteId: roleId,
76
+ });
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ try {
85
+ const requestDefaults = await (0, api_1.queryRequestDefaults)(cmd, client, requestedResources, requestedGroups);
86
+ if (requestDefaults !== undefined) {
87
+ metadata.requestDefaults.durationOptions =
88
+ requestDefaults.durationOptions;
89
+ metadata.requestDefaults.recommendedDurationInMinutes =
90
+ requestDefaults.recommendedDurationInMinutes;
91
+ metadata.requestDefaults.defaultDurationInMinutes =
92
+ requestDefaults.defaultDurationInMinutes;
93
+ metadata.requestDefaults.maxDurationInMinutes =
94
+ requestDefaults.maxDurationInMinutes;
95
+ metadata.requestDefaults.requireSupportTicket =
96
+ requestDefaults.requireSupportTicket;
97
+ metadata.requestDefaults.reasonOptional = requestDefaults.reasonOptional;
98
+ metadata.requestDefaults.requesterIsAdmin =
99
+ requestDefaults.requesterIsAdmin;
100
+ for (const message of requestDefaults.messages || []) {
101
+ let connectionName = undefined;
102
+ let connectionType = undefined;
103
+ // If the message has an entityId, retrieve the connection name and type
104
+ if (message.entityId) {
105
+ for (const appNode of Object.values(requestMap)) {
106
+ for (const assetNode of Object.values(appNode.assets)) {
107
+ if (assetNode.assetId === message.entityId) {
108
+ connectionName = appNode.appName;
109
+ connectionType = appNode.appType;
110
+ break;
111
+ }
112
+ }
113
+ }
114
+ }
115
+ // Log the request message based on the code
116
+ cmd.log(chalk_1.default.dim(`\n${chalk_1.default.italic(message.level)}:`), getRequestMessageFromCode(cmd, message.code, connectionName, connectionType));
117
+ if (message.level === "ERROR") {
118
+ process.exit(1);
119
+ }
120
+ }
121
+ if (requestDefaults.requireSupportTicket) {
122
+ cmd.log("\nA support ticket is required for this request. Please submit through the Opal website.");
123
+ const requestLink = generateRequestLink(cmd, (_a = metadata.requestDefaults.defaultDurationInMinutes) !== null && _a !== void 0 ? _a : 60);
124
+ cmd.log(`${chalk_1.default.bold("Link:")} ${requestLink}\n`);
125
+ process.exit(1);
126
+ }
127
+ }
128
+ }
129
+ catch (_b) {
130
+ cmd.error("Error fetching request defaults.");
131
+ }
132
+ }
133
+ async function submitFinalRequest(cmd, client, metadata) {
134
+ var _a, _b, _c, _d;
135
+ // Build requested assets lists for the mutation
136
+ const requestedResources = [];
137
+ const requestedGroups = [];
138
+ for (const appNode of Object.values(metadata.requestMap)) {
139
+ // This extraction is different than the one in setRequestDefaults.
140
+ // Both extract the requestedResources and requestedGroups,
141
+ // use different formats.
142
+ for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
143
+ if (assetNode.roles) {
144
+ const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
145
+ return roleId;
146
+ });
147
+ const roleIds = mappedRoles.length > 0 ? mappedRoles : [""];
148
+ for (const roleId of roleIds) {
149
+ switch (assetNode.type) {
150
+ case graphql_1.EntityType.Resource: {
151
+ requestedResources.push({
152
+ resourceId: assetId,
153
+ accessLevel: {
154
+ accessLevelName: ((_b = (_a = assetNode.roles) === null || _a === void 0 ? void 0 : _a[roleId]) === null || _b === void 0 ? void 0 : _b.roleName) || "",
155
+ accessLevelRemoteId: roleId,
156
+ },
157
+ });
158
+ break;
159
+ }
160
+ case graphql_1.EntityType.Group: {
161
+ requestedGroups.push({
162
+ groupId: assetId,
163
+ accessLevel: {
164
+ accessLevelName: ((_d = (_c = assetNode.roles) === null || _c === void 0 ? void 0 : _c[roleId]) === null || _d === void 0 ? void 0 : _d.roleName) || "",
165
+ accessLevelRemoteId: roleId,
166
+ },
167
+ });
168
+ break;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ const resp = await (0, api_1.createRequest)(cmd, client, requestedResources, requestedGroups, metadata.reason, metadata.durationInMinutes);
176
+ // Build link to request
177
+ if (resp === null || resp === void 0 ? void 0 : resp.id) {
178
+ cmd.log("\n🎉 Your Access Request has been submitted!\n");
179
+ cmd.log(`${chalk_1.default.bold("ID:")} ${chalk_1.default.cyan(resp.id)}`);
180
+ if (resp === null || resp === void 0 ? void 0 : resp.status) {
181
+ cmd.log((0, displays_1.getStyledStatus)(resp.status));
182
+ }
183
+ const requestLink = getRequestLink(cmd, resp.id);
184
+ cmd.log(`${chalk_1.default.bold("Link:")} ${chalk_1.default.underline(requestLink)}\n`);
185
+ (0, displays_1.displayRequestAgain)(cmd, resp.id);
186
+ }
187
+ return;
188
+ }
189
+ function getRequestLink(cmd, id) {
190
+ const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
191
+ return `${configData[config_1.urlKey]}/requests/sent/${id}`;
192
+ }
193
+ function generateRequestLink(cmd, defaultDurationInMinutes) {
194
+ const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
195
+ // Including the duration in the URL so that the cancel button on the request page works as expected
196
+ return `${configData[config_1.urlKey]}/request-access?durationInMinutes=${defaultDurationInMinutes}`;
197
+ }
198
+ async function bypassRequestSelection(cmd, client, flagValue, metadata) {
199
+ var _a, _b, _c, _d;
200
+ try {
201
+ // Query Catalog Item endpoint to identify what the id belongs to (resource or group)
202
+ for (const val of flagValue) {
203
+ const delimiterIndex = val.indexOf(":");
204
+ const assetId = delimiterIndex === -1 ? val : val.substring(0, delimiterIndex);
205
+ const roleName = delimiterIndex === -1 ? "" : val.substring(delimiterIndex + 1);
206
+ const resp = await (0, api_1.queryCatalogItems)(cmd, client, assetId);
207
+ switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.catalogItem.__typename) {
208
+ case "Group":
209
+ case "Resource": {
210
+ const item = (_b = resp.data) === null || _b === void 0 ? void 0 : _b.catalogItem;
211
+ const assetName = item.__typename === "Resource" ? item.displayName : item.name;
212
+ const requestableRoles = (item.accessLevels || [])
213
+ // TODO: Support okta azure apps ?.filter((role) => role.accessLevelName !== "") // This assumes length == 1
214
+ .map((role) => ({
215
+ id: role.accessLevelRemoteId,
216
+ name: role.accessLevelName,
217
+ }));
218
+ const appId = ((_c = item.connection) === null || _c === void 0 ? void 0 : _c.id) || "";
219
+ if (!(appId in metadata.requestMap)) {
220
+ metadata.requestMap[appId] = {
221
+ appName: ((_d = item.connection) === null || _d === void 0 ? void 0 : _d.displayName) || "",
222
+ appId: appId,
223
+ assets: {},
224
+ };
225
+ }
226
+ const assetEntry = metadata.requestMap[appId].assets[assetId];
227
+ if (!assetEntry) {
228
+ metadata.requestMap[appId].assets[assetId] = {
229
+ assetId: assetId,
230
+ assetName: assetName,
231
+ type: (0, types_1.entityTypeFromString)(item.__typename),
232
+ roles: {},
233
+ };
234
+ }
235
+ if (requestableRoles.length > 0 &&
236
+ !(requestableRoles.length === 1 && requestableRoles[0].name === "")) {
237
+ const selectedRole = requestableRoles.find((role) => role.name === roleName);
238
+ if (selectedRole !== undefined) {
239
+ if (!metadata.requestMap[appId].assets[assetId].roles) {
240
+ metadata.requestMap[appId].assets[assetId].roles = {};
241
+ }
242
+ metadata.requestMap[appId].assets[assetId].roles[selectedRole.id] = {
243
+ roleId: selectedRole.id,
244
+ roleName: selectedRole.name,
245
+ };
246
+ }
247
+ else {
248
+ cmd.error(`Access level specified does not match one of ${assetName}'s defined access levels: ${requestableRoles.map((role) => `"${role.name}"`)}`);
249
+ }
250
+ }
251
+ break;
252
+ }
253
+ default:
254
+ cmd.error("Invalid asset id was passed in using the --id flag.");
255
+ }
256
+ }
257
+ }
258
+ catch (error) {
259
+ if (error instanceof Error || typeof error === "string") {
260
+ cmd.error(error);
261
+ }
262
+ }
263
+ return;
264
+ }
265
+ function bypassDuration(cmd, duration, metadata) {
266
+ const maxDuration = metadata.requestDefaults.maxDurationInMinutes;
267
+ // Permanent duration is represented by 0, but should not be allowed
268
+ // if a max duration is set.
269
+ if (maxDuration && (duration > maxDuration || duration === 0)) {
270
+ cmd.error(`The requested duration exceeds the allowed limit of ${(0, displays_1.formatDuration)(maxDuration)}. Please choose a shorter duration.`);
271
+ }
272
+ if (duration === 0) {
273
+ metadata.durationInMinutes = undefined;
274
+ }
275
+ else {
276
+ metadata.durationInMinutes = duration;
277
+ }
278
+ }
279
+ function getRequestMessageFromCode(cmd, code, connectionName, connectionType, extraParams,
280
+ // sourceGroup?: PropsFor<typeof GroupBindingGroupLabel>["group"];
281
+ sourceGroupRedirect) {
282
+ switch (code) {
283
+ case graphql_1.RequestMessageCode.RequireUserAuthToken: {
284
+ if (connectionType) {
285
+ const connectionLabel = labels_1.connectionTypeLabelByType[connectionType];
286
+ // This case the connection has a third party provider such as GitLab,
287
+ // GitHub that requires the use to create a manual step into the end
288
+ // system.
289
+ const isThirdPartyProvider = Object.values(graphql_1.ThirdPartyProvider).find((v) => v === connectionType);
290
+ if (isThirdPartyProvider) {
291
+ const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
292
+ return `This item requires you to link your ${connectionLabel} account to Opal before requesting access.
293
+ You can link your ${connectionLabel} account at ${`${configData[config_1.urlKey]}/user/settings/identities`}`;
294
+ }
295
+ const name = connectionName !== null && connectionName !== void 0 ? connectionName : connectionLabel;
296
+ // This case would be hit in case the user is not provisioned onto the end system, such as AWS, GCP, Okta, etc.
297
+ return `This item requires you to be provisioned on ${name} before requesting access.\
298
+ Please contact your Opal admin to provision your user on ${name}.`;
299
+ }
300
+ // This should never happen, but just in case we forgot to pass in the third party provider or the connection type
301
+ return "Your user does not exist on the end system. Please contact your Opal admin to add your user to the end system.";
302
+ }
303
+ case graphql_1.RequestMessageCode.NestedGroupAccessNotAllowed:
304
+ return "You cannot request access to this group because you already have nested access.";
305
+ case graphql_1.RequestMessageCode.LinkedGroupNotRequestable:
306
+ return "You cannot request access to this group because it is linked to another group";
307
+ default:
308
+ return `Unknown request message code: ${code}`;
309
+ }
310
+ }
311
+ function addRequestedResourcesToMetadata(requestedResources, requestMap) {
312
+ var _a;
313
+ for (const { resource, accessLevel } of requestedResources) {
314
+ if (!resource)
315
+ continue;
316
+ const { id: assetId, displayName: assetName, connection, connectionId, __typename, } = resource;
317
+ const type = (0, types_1.entityTypeFromString)(__typename);
318
+ const roleId = accessLevel.accessLevelRemoteId;
319
+ const roleName = accessLevel.accessLevelName;
320
+ if (!requestMap[connectionId]) {
321
+ requestMap[connectionId] = {
322
+ appId: connectionId,
323
+ appName: (_a = connection === null || connection === void 0 ? void 0 : connection.name) !== null && _a !== void 0 ? _a : "",
324
+ appType: connection === null || connection === void 0 ? void 0 : connection.connectionType,
325
+ assets: {},
326
+ };
327
+ }
328
+ const appAssets = requestMap[connectionId].assets;
329
+ if (!appAssets[assetId]) {
330
+ appAssets[assetId] = {
331
+ assetId,
332
+ assetName,
333
+ type,
334
+ roles: {},
335
+ };
336
+ }
337
+ if (!appAssets[assetId].roles) {
338
+ appAssets[assetId].roles = {};
339
+ }
340
+ appAssets[assetId].roles[roleId] = { roleId, roleName };
341
+ }
342
+ }
343
+ function addRequestedGroupsToMetadata(requestedGroups, requestMap) {
344
+ var _a;
345
+ for (const { group, accessLevel } of requestedGroups) {
346
+ if (!group)
347
+ continue;
348
+ const { id: assetId, name: assetName, connection, connectionId, __typename, } = group;
349
+ const type = (0, types_1.entityTypeFromString)(__typename);
350
+ const roleId = accessLevel === null || accessLevel === void 0 ? void 0 : accessLevel.accessLevelRemoteId;
351
+ const roleName = accessLevel === null || accessLevel === void 0 ? void 0 : accessLevel.accessLevelName;
352
+ if (!requestMap[connectionId]) {
353
+ requestMap[connectionId] = {
354
+ appId: connectionId,
355
+ appName: (_a = connection === null || connection === void 0 ? void 0 : connection.name) !== null && _a !== void 0 ? _a : "",
356
+ appType: connection === null || connection === void 0 ? void 0 : connection.connectionType,
357
+ assets: {},
358
+ };
359
+ }
360
+ const appAssets = requestMap[connectionId].assets;
361
+ if (!appAssets[assetId]) {
362
+ appAssets[assetId] = {
363
+ assetId,
364
+ assetName,
365
+ type,
366
+ roles: {},
367
+ };
368
+ }
369
+ if (!appAssets[assetId].roles) {
370
+ appAssets[assetId].roles = {};
371
+ }
372
+ if (roleId) {
373
+ appAssets[assetId].roles[roleId] = { roleId, roleName: roleName !== null && roleName !== void 0 ? roleName : "" };
374
+ }
375
+ }
376
+ }
377
+ async function convertRequestToMetadata(cmd, request, metadata) {
378
+ const { status, durationInMinutes, reason, requestedResources, requestedGroups, } = request;
379
+ if (status === graphql_1.RequestStatus.Pending) {
380
+ cmd.log("⏳ Request is still in progress");
381
+ return;
382
+ }
383
+ if (durationInMinutes === undefined) {
384
+ cmd.error("Duration in minutes is required but was not provided.");
385
+ }
386
+ // if durationInMinutes is null, the request had a permanent duration
387
+ metadata.durationInMinutes = durationInMinutes !== null && durationInMinutes !== void 0 ? durationInMinutes : 0;
388
+ metadata.reason = reason;
389
+ addRequestedResourcesToMetadata(requestedResources, metadata.requestMap);
390
+ addRequestedGroupsToMetadata(requestedGroups, metadata.requestMap);
391
+ }
392
+ async function duplicateRequestTemplate(cmd, client, requestId, metadata) {
393
+ var _a, _b, _c, _d;
394
+ cmd.log("Loading request template from ID: ", requestId);
395
+ const resp = await (0, api_1.queryRequest)(client, requestId);
396
+ // no fall through doesn't consider process.exit();
397
+ let x;
398
+ switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.request.__typename) {
399
+ case "RequestResult": {
400
+ if (((_b = resp.data) === null || _b === void 0 ? void 0 : _b.request.request).status ===
401
+ graphql_1.RequestStatus.Pending) {
402
+ cmd.error("⏳ Cannot duplicate a request that is still in progress");
403
+ }
404
+ cmd.log("Creating new request with same configuration...");
405
+ convertRequestToMetadata(cmd, (_d = (_c = resp.data) === null || _c === void 0 ? void 0 : _c.request) === null || _d === void 0 ? void 0 : _d.request, metadata);
406
+ break;
407
+ }
408
+ case "RequestNotFoundError":
409
+ x = cmd.error(`🚫 Request with id ${requestId} was not found`);
410
+ break;
411
+ default:
412
+ cmd.error("🚫 Error retrieving request data");
413
+ }
414
+ }
415
+ async function convertBundleToMetadata(cmd, bundle, requestMap) {
416
+ const { name, id, items } = bundle;
417
+ const requestedResources = [];
418
+ const requestedGroups = [];
419
+ let notRequestableCount = 0;
420
+ for (const item of items.edges) {
421
+ if (item.node.isRequestable) {
422
+ if (item.node.__typename === "Resource") {
423
+ requestedResources.push({
424
+ resource: item.node,
425
+ accessLevel: item.accessLevel,
426
+ });
427
+ }
428
+ else if (item.node.__typename === "Group") {
429
+ requestedGroups.push({
430
+ group: item.node,
431
+ accessLevel: item.accessLevel,
432
+ });
433
+ }
434
+ }
435
+ else {
436
+ notRequestableCount++;
437
+ }
438
+ }
439
+ addRequestedResourcesToMetadata(requestedResources, requestMap);
440
+ addRequestedGroupsToMetadata(requestedGroups, requestMap);
441
+ const requestableCount = requestedResources.length + requestedGroups.length;
442
+ if (requestableCount === 0) {
443
+ cmd.error(`No requestable items in the bundle: ${name}`);
444
+ }
445
+ if (notRequestableCount > 0) {
446
+ cmd.log(`You do not have permission to request access to ${notRequestableCount} items in this bundle`);
447
+ }
448
+ cmd.log("Added all requestable items in the bundle");
449
+ }
450
+ async function copyBundleAssets(cmd, client, bundleId, requestMap) {
451
+ var _a, _b;
452
+ cmd.log("Loading assets from bundle: ", bundleId);
453
+ const resp = await (0, requests_1.queryBundle)(client, bundleId);
454
+ // no fall through doesn't consider process.exit();
455
+ let x;
456
+ switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.bundle.__typename) {
457
+ case "BundleResult": {
458
+ cmd.log("Creating new request with assets in the bundle...");
459
+ convertBundleToMetadata(cmd, (_b = resp.data) === null || _b === void 0 ? void 0 : _b.bundle.bundle, requestMap);
460
+ break;
461
+ }
462
+ case "BundleNotFoundError":
463
+ x = cmd.error(`🚫 Bundle with id ${bundleId} was not found`);
464
+ break;
465
+ default:
466
+ cmd.error("🚫 Error retrieving bundle data");
467
+ }
468
+ }
@@ -0,0 +1,55 @@
1
+ import { type ConnectionType, EntityType, type RequestMessageCode, type RequestMessageLevel } from "../../graphql/graphql";
2
+ type AppNode = {
3
+ appId: string;
4
+ appName: string;
5
+ appType?: ConnectionType;
6
+ assets: Record<string, AssetNode>;
7
+ };
8
+ type AssetNode = {
9
+ assetId: string;
10
+ assetName: string;
11
+ type: EntityType;
12
+ roles?: Record<string, RoleNode>;
13
+ };
14
+ type RoleNode = {
15
+ roleId: string;
16
+ roleName: string;
17
+ };
18
+ export type RequestMap = Record<string, AppNode>;
19
+ export declare function entityTypeFromString(str?: string): EntityType;
20
+ export type DurationOption = {
21
+ durationInMinutes: number;
22
+ label: string;
23
+ };
24
+ export type RequestDefaults = {
25
+ durationOptions?: DurationOption[];
26
+ recommendedDurationInMinutes?: number | null;
27
+ defaultDurationInMinutes?: number;
28
+ maxDurationInMinutes?: number | null;
29
+ requireSupportTicket?: boolean;
30
+ reasonOptional?: boolean;
31
+ requesterIsAdmin?: boolean;
32
+ messages?: {
33
+ entityId?: string | null;
34
+ level: RequestMessageLevel;
35
+ code: RequestMessageCode;
36
+ }[];
37
+ };
38
+ export type RequestMetadata = {
39
+ requestMap: RequestMap;
40
+ requestDefaults: RequestDefaults;
41
+ durationLabel: string;
42
+ durationInMinutes?: number;
43
+ reason: string;
44
+ };
45
+ export type EntityValue = {
46
+ id: string;
47
+ name: string;
48
+ type?: string;
49
+ toString?: () => string;
50
+ };
51
+ export type PromptChoice = {
52
+ message: string;
53
+ value: EntityValue;
54
+ };
55
+ export {};
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entityTypeFromString = entityTypeFromString;
4
+ const graphql_1 = require("../../graphql/graphql");
5
+ function entityTypeFromString(str) {
6
+ const capStr = str === null || str === void 0 ? void 0 : str.toLocaleUpperCase();
7
+ if (capStr === "RESOURCE") {
8
+ return graphql_1.EntityType.Resource;
9
+ }
10
+ if (capStr === "GROUP") {
11
+ return graphql_1.EntityType.Group;
12
+ }
13
+ // if type unknown, default to resource
14
+ return graphql_1.EntityType.Resource;
15
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Command } from "@oclif/core";
2
- import type { ResourceAccessLevel, ResourceAccessLevelInput } from "../types";
2
+ import type { ResourceAccessLevel, ResourceAccessLevelInput } from "../graphql/graphql";
3
3
  export type ResourceInfo = {
4
4
  id: string;
5
5
  name: string;
@@ -1,4 +1,4 @@
1
1
  import type { Command } from "@oclif/core";
2
- import type { ResourceAccessLevelInput } from "../types";
2
+ import type { ResourceAccessLevelInput } from "../graphql/graphql";
3
3
  export declare const getOrCreateSession: (command: Command, resourceId: string, accessLevel: ResourceAccessLevelInput, sessionId: string | undefined, metadataFragment: string, wantNewSession?: boolean) => Promise<any>;
4
4
  export declare const getSessionExpirationMessage: (session: any) => string;
@@ -118,6 +118,7 @@ const openBrowserAndPollForSession = async (command, message, resourceId, access
118
118
  return session;
119
119
  };
120
120
  const createSession = async (command, resourceId, accessLevel, sessionId, metadataFragment, wantNewSession) => {
121
+ var _a, _b, _c, _d;
121
122
  const { resp, error } = await (0, handler_1.runMutation)({
122
123
  command: command,
123
124
  query: CreateSessionDocument.replace("METADATA_FRAGMENT", metadataFragment),
@@ -130,9 +131,9 @@ const createSession = async (command, resourceId, accessLevel, sessionId, metada
130
131
  if (error) {
131
132
  return (0, apollo_1.handleError)(command, error);
132
133
  }
133
- switch (resp === null || resp === void 0 ? void 0 : resp.data.createSession.__typename) {
134
+ switch ((_b = (_a = resp === null || resp === void 0 ? void 0 : resp.data) === null || _a === void 0 ? void 0 : _a.createSession) === null || _b === void 0 ? void 0 : _b.__typename) {
134
135
  case "CreateSessionResult": {
135
- return resp.data.createSession.session;
136
+ return (_d = (_c = resp.data) === null || _c === void 0 ? void 0 : _c.createSession) === null || _d === void 0 ? void 0 : _d.session;
136
137
  }
137
138
  case "MfaInvalidError": {
138
139
  return openBrowserAndPollForSession(command, "❗ MFA validation needed. Please connect via browser. Opening browser and awaiting validation...", resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment, wantNewSession);
package/lib/lib/util.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export declare function restrictToDev(): void;
1
2
  export declare const sleep: (ms: number) => Promise<unknown>;
2
3
  export declare const copyToClipboard: (content: string) => import("child_process").ChildProcess;
3
4
  export declare const displayContent: (content: string) => import("child_process").ChildProcess;
package/lib/lib/util.js CHANGED
@@ -1,7 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.displayContent = exports.copyToClipboard = exports.sleep = void 0;
4
+ exports.restrictToDev = restrictToDev;
4
5
  const node_child_process_1 = require("node:child_process");
6
+ /*
7
+ Use restrictToDev function in the run functions of commands still in development-
8
+
9
+ static hidden = true; # Use this in tandem with restrictToDev function to hide from help menu.
10
+ async run() {
11
+ restrictToDev();
12
+ ...
13
+ }
14
+ */
15
+ function restrictToDev() {
16
+ if (process.env.NODE_ENV !== "development") {
17
+ console.error("Command still under development. Please look out for product announcements for official release.");
18
+ process.exit(1);
19
+ }
20
+ }
5
21
  const sleep = (ms) => {
6
22
  return new Promise((resolve) => {
7
23
  setTimeout(resolve, ms);
package/lib/types.d.ts CHANGED
@@ -1047,20 +1047,36 @@ export type ConnectionResult = {
1047
1047
  };
1048
1048
  export declare enum ConnectionType {
1049
1049
  ActiveDirectory = "ACTIVE_DIRECTORY",
1050
+ /**
1051
+ * Deprecated. Legacy integration no longer offered - use AWS_SSO instead.
1052
+ * @deprecated Legacy integration no longer offered - use AWS_SSO instead.
1053
+ */
1050
1054
  Aws = "AWS",
1055
+ AwsSso = "AWS_SSO",
1056
+ AzureAd = "AZURE_AD",
1051
1057
  Custom = "CUSTOM",
1058
+ CustomConnector = "CUSTOM_CONNECTOR",
1059
+ Databricks = "DATABRICKS",
1052
1060
  Duo = "DUO",
1053
- GitHub = "GIT_HUB",
1054
1061
  Gcp = "GCP",
1062
+ GitHub = "GIT_HUB",
1063
+ GitLab = "GIT_LAB",
1055
1064
  GoogleGroups = "GOOGLE_GROUPS",
1056
1065
  GoogleWorkspace = "GOOGLE_WORKSPACE",
1057
- Salesforce = "SALESFORCE",
1058
1066
  Ldap = "LDAP",
1067
+ Mariadb = "MARIADB",
1059
1068
  Mongo = "MONGO",
1060
1069
  MongoAtlas = "MONGO_ATLAS",
1070
+ Mysql = "MYSQL",
1061
1071
  OktaDirectory = "OKTA_DIRECTORY",
1062
1072
  Opal = "OPAL",
1063
- Pagerduty = "PAGERDUTY"
1073
+ Pagerduty = "PAGERDUTY",
1074
+ Postgres = "POSTGRES",
1075
+ Salesforce = "SALESFORCE",
1076
+ Snowflake = "SNOWFLAKE",
1077
+ Tailscale = "TAILSCALE",
1078
+ Teleport = "TELEPORT",
1079
+ Workday = "WORKDAY"
1064
1080
  }
1065
1081
  export type ConnectionUrlInvalidError = Error & {
1066
1082
  __typename?: "ConnectionURLInvalidError";