opal-security 3.1.1-beta.8a533e4 → 3.1.1-beta.981ec0b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,29 @@
1
1
  import type { NormalizedCacheObject } from "@apollo/client/core";
2
2
  import type { ApolloClient } from "@apollo/client/core/ApolloClient";
3
3
  import type { Command } from "@oclif/core/lib/command";
4
- interface AppNode {
4
+ import { type AppType, type ConnectionType, EntityType } from "../graphql/graphql";
5
+ type AppNode = {
6
+ appId: string;
5
7
  appName: string;
8
+ appType?: AppType | ConnectionType;
6
9
  assets: Record<string, AssetNode>;
7
- }
8
- interface AssetNode {
10
+ };
11
+ type AssetNode = {
12
+ assetId: string;
9
13
  assetName: string;
10
- type: string;
14
+ type: EntityType;
11
15
  roles?: Record<string, RoleNode>;
12
- }
13
- interface RoleNode {
16
+ };
17
+ type RoleNode = {
18
+ roleId: string;
14
19
  roleName: string;
15
- }
20
+ };
16
21
  export type RequestMap = Record<string, AppNode>;
17
- interface DurationOption {
22
+ type DurationOption = {
18
23
  durationInMinutes: number;
19
24
  label: string;
20
- }
21
- interface RequestDefaults {
25
+ };
26
+ type RequestDefaults = {
22
27
  durationOptions?: DurationOption[];
23
28
  recommendedDurationInMinutes?: number | null;
24
29
  defaultDurationInMinutes?: number;
@@ -26,21 +31,22 @@ interface RequestDefaults {
26
31
  requireSupportTicket?: boolean;
27
32
  reasonOptional?: boolean;
28
33
  requesterIsAdmin?: boolean;
29
- }
30
- export interface RequestMetadata {
34
+ };
35
+ export type RequestMetadata = {
31
36
  requestMap: RequestMap;
32
37
  requestDefaults: RequestDefaults;
33
38
  durationLabel: string;
34
39
  durationInMinutes?: number;
35
40
  reason: string;
36
- }
41
+ };
37
42
  export declare function initEmptyRequestMetadata(): RequestMetadata;
38
43
  export declare function selectRequestableItems(cmd: Command, client: ApolloClient<NormalizedCacheObject>, requestMap: RequestMap): Promise<void>;
39
- export declare function chooseAssets(cmd: Command, client: ApolloClient<NormalizedCacheObject>, appId: string, requestMap: RequestMap): Promise<void>;
40
- export declare function chooseRoles(cmd: Command, client: ApolloClient<NormalizedCacheObject>, appId: string, assetId: string, requestMap: RequestMap): Promise<void>;
41
44
  export declare function doneSelectingAssets(): Promise<boolean>;
42
45
  export declare function setRequestDefaults(cmd: Command, client: ApolloClient<NormalizedCacheObject>, metadata: RequestMetadata): Promise<void>;
43
46
  export declare function promptForReason(metadata: RequestMetadata): Promise<void>;
44
47
  export declare function promptForExpiration(metadata: RequestMetadata): Promise<void>;
48
+ export declare function promptRequestSubmission(cmd: Command, metadata: RequestMetadata): Promise<void>;
45
49
  export declare function submitFinalRequest(cmd: Command, client: ApolloClient<NormalizedCacheObject>, metadata: RequestMetadata): Promise<void>;
50
+ export declare function bypassRequestSelection(cmd: Command, client: ApolloClient<NormalizedCacheObject>, flagValue: string[], metadata: RequestMetadata): Promise<void>;
51
+ export declare function bypassDuration(cmd: Command, duration: number, metadata: RequestMetadata): void;
46
52
  export {};
@@ -2,19 +2,31 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
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;
12
13
  const chalk_1 = require("chalk");
13
14
  const inquirer = require("inquirer");
14
15
  const graphql_1 = require("../graphql");
16
+ const graphql_2 = require("../graphql/graphql");
15
17
  const displays_1 = require("../utils/displays");
16
18
  const config_1 = require("./config");
17
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
+ }
18
30
  function initEmptyRequestMetadata() {
19
31
  // Initialize with empty defaults
20
32
  const requestDefaults = {
@@ -94,6 +106,7 @@ async function queryRequestableApps(cmd, client, input) {
94
106
  value: {
95
107
  id: edge.node.id,
96
108
  name: edge.node.displayName,
109
+ type: type,
97
110
  toString: () => edge.node.displayName,
98
111
  },
99
112
  };
@@ -485,39 +498,245 @@ async function createRequest(cmd, client, requestedResources, requestedGroups, r
485
498
  }
486
499
  }
487
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
+ }
488
625
  // Helper functions
489
626
  async function selectRequestableItems(cmd, client, requestMap) {
490
- const initialChoices = (await queryRequestableApps(cmd, client, "")) || [];
627
+ const initial = (await queryRequestableApps(cmd, client, "")) || [];
491
628
  const appPrompt = new AutoComplete({
492
629
  name: "App",
493
630
  message: "Select an app:",
494
631
  limit: 15,
495
- choices: initialChoices,
632
+ choices: initial,
496
633
  async suggest(input) {
497
634
  const filteredChoices = await queryRequestableApps(cmd, client, input || "");
498
- return filteredChoices || initialChoices;
635
+ return filteredChoices || initial;
499
636
  },
500
637
  });
501
638
  const App = await appPrompt.run();
502
639
  // Set the app in the requestMap and call choose assets step
503
640
  if (!(App.id in requestMap)) {
504
641
  requestMap[App.id] = {
642
+ appId: App.id,
505
643
  appName: App.name,
506
644
  assets: {},
507
645
  };
508
646
  }
647
+ if (App.type === "OKTA_APP" || App.type === "AZURE_ENTERPRISE_APP") {
648
+ await chooseOktaAzureRoles(cmd, client, App, requestMap);
649
+ return;
650
+ }
509
651
  await chooseAssets(cmd, client, App.id, requestMap);
510
652
  }
653
+ async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
654
+ const associatedItems = (await queryAssociatedItems(cmd, client, app.id, "")) || [];
655
+ const rolePrompt = new AutoComplete({
656
+ name: "Roles",
657
+ message: `Select a role for ${app.name}:`,
658
+ limit: 15,
659
+ multiple: true,
660
+ async choices(input) {
661
+ if (!input)
662
+ return associatedItems;
663
+ const filteredChoices = await queryAssociatedItems(cmd, client, app.id, input);
664
+ return filteredChoices || associatedItems;
665
+ },
666
+ validate: (answer) => {
667
+ if (answer.length !== 1) {
668
+ return "You must select only one item.";
669
+ }
670
+ return true;
671
+ },
672
+ });
673
+ const Roles = await rolePrompt.run();
674
+ const entry = requestMap[app.id];
675
+ for (const role of Roles) {
676
+ if (!(role.id in entry.assets)) {
677
+ entry.assets[role.id] = {
678
+ assetId: role.id,
679
+ assetName: role.name,
680
+ type: entityTypeFromString(role.type),
681
+ roles: {},
682
+ };
683
+ }
684
+ }
685
+ }
686
+ function appRolesFromEdge(edge) {
687
+ var _a, _b, _c, _d;
688
+ switch (edge.node.__typename) {
689
+ case "Resource": {
690
+ if (edge.node.accessLevels && edge.node.accessLevels.length > 0) {
691
+ return edge.node.accessLevels.map((accessLevel) => ({
692
+ message: accessLevel.accessLevelName || "No Role (Direct access)",
693
+ value: {
694
+ id: edge.node.id + accessLevel.accessLevelRemoteId,
695
+ name: accessLevel.accessLevelName,
696
+ type: graphql_2.EntityType.Resource,
697
+ toString: () => accessLevel.accessLevelName,
698
+ },
699
+ }));
700
+ }
701
+ return [
702
+ {
703
+ message: (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name,
704
+ value: {
705
+ id: edge.node.id,
706
+ name: (_b = edge.alias) !== null && _b !== void 0 ? _b : edge.node.name,
707
+ type: graphql_2.EntityType.Resource,
708
+ toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
709
+ },
710
+ },
711
+ ];
712
+ }
713
+ case "Group":
714
+ return [
715
+ {
716
+ message: (_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name,
717
+ value: {
718
+ id: edge.node.id,
719
+ name: (_d = edge.alias) !== null && _d !== void 0 ? _d : edge.node.name,
720
+ type: graphql_2.EntityType.Group,
721
+ toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
722
+ },
723
+ },
724
+ ];
725
+ }
726
+ }
511
727
  async function chooseAssets(cmd, client, appId, requestMap) {
512
- const initialChoices = (await queryRequestableAssets(cmd, client, appId, "")) || [];
728
+ const initial = (await queryRequestableAssets(cmd, client, appId, "")) || [];
513
729
  const assetPrompt = new AutoComplete({
514
730
  name: "Assets",
515
731
  message: "Select one or more assets:",
516
732
  limit: 15,
517
733
  multiple: true,
518
734
  async choices(input) {
735
+ if (!input) {
736
+ return initial;
737
+ }
519
738
  const filteredChoices = await queryRequestableAssets(cmd, client, appId, input);
520
- return filteredChoices || initialChoices;
739
+ return filteredChoices || initial;
521
740
  },
522
741
  validate: (answer) => {
523
742
  if (answer.length < 1) {
@@ -534,6 +753,7 @@ async function chooseAssets(cmd, client, appId, requestMap) {
534
753
  }
535
754
  if (!(asset.id in entry.assets)) {
536
755
  entry.assets[asset.id] = {
756
+ assetId: asset.id,
537
757
  assetName: asset.name,
538
758
  type: asset.type,
539
759
  roles: {},
@@ -574,6 +794,7 @@ async function chooseRoles(cmd, client, appId, assetId, requestMap) {
574
794
  }
575
795
  for (const role of roles) {
576
796
  assetEntry.roles[role.id] = {
797
+ roleId: role.id,
577
798
  roleName: role.name,
578
799
  };
579
800
  }
@@ -602,14 +823,14 @@ async function setRequestDefaults(cmd, client, metadata) {
602
823
  const roleIds = mappedRoles.length ? mappedRoles : [""];
603
824
  for (const roleId of roleIds) {
604
825
  switch (assetNode.type) {
605
- case "Resource": {
826
+ case graphql_2.EntityType.Resource: {
606
827
  requestedResources.push({
607
828
  resourceId: assetId,
608
829
  accessLevelRemoteId: roleId,
609
830
  });
610
831
  break;
611
832
  }
612
- case "Group": {
833
+ case graphql_2.EntityType.Group: {
613
834
  requestedGroups.push({
614
835
  groupId: assetId,
615
836
  accessLevelRemoteId: roleId,
@@ -746,7 +967,7 @@ async function setCustomDuration(metadata) {
746
967
  var _a, _b, _c;
747
968
  const { d, h, m } = getDurationNumbers(answer);
748
969
  const durationInMinutes = getDurationInMinutes(answer);
749
- if (d < 0 || h < 0 || m < 0 || d + h + m > 0 || (h > 23 && m > 59)) {
970
+ if (d < 0 || h < 0 || m < 0 || d + h + m === 0 || (h > 23 && m > 59)) {
750
971
  return "Please enter a valid duration.";
751
972
  }
752
973
  if (((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes) &&
@@ -769,8 +990,8 @@ async function setCustomDuration(metadata) {
769
990
  label: durationLabel,
770
991
  };
771
992
  }
772
- async function submitFinalRequest(cmd, client, metadata) {
773
- var _a, _b, _c, _d;
993
+ async function promptRequestSubmission(cmd, metadata) {
994
+ (0, displays_1.displayFinalRequestSummary)(cmd, metadata);
774
995
  const submitMessage = "āœ… Yes, submit request";
775
996
  const cancelMessage = "āŒ No, cancel request";
776
997
  const { submit } = await inquirer.prompt([
@@ -783,55 +1004,6 @@ async function submitFinalRequest(cmd, client, metadata) {
783
1004
  ]);
784
1005
  switch (submit) {
785
1006
  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
1007
  return;
836
1008
  }
837
1009
  case cancelMessage: {
@@ -843,3 +1015,142 @@ async function submitFinalRequest(cmd, client, metadata) {
843
1015
  }
844
1016
  }
845
1017
  }
1018
+ async function submitFinalRequest(cmd, client, metadata) {
1019
+ var _a, _b, _c, _d;
1020
+ // Build requested assets lists for the mutation
1021
+ const requestedResources = [];
1022
+ const requestedGroups = [];
1023
+ for (const appNode of Object.values(metadata.requestMap)) {
1024
+ // This extraction is different than the one in setRequestDefaults.
1025
+ // Both extract the requestedResources and requestedGroups,
1026
+ // use different formats.
1027
+ for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
1028
+ if (assetNode.roles) {
1029
+ const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
1030
+ return roleId;
1031
+ });
1032
+ const roleIds = mappedRoles.length > 0 ? mappedRoles : [""];
1033
+ for (const roleId of roleIds) {
1034
+ switch (assetNode.type) {
1035
+ case graphql_2.EntityType.Resource: {
1036
+ requestedResources.push({
1037
+ resourceId: assetId,
1038
+ accessLevel: {
1039
+ accessLevelName: ((_b = (_a = assetNode.roles) === null || _a === void 0 ? void 0 : _a[roleId]) === null || _b === void 0 ? void 0 : _b.roleName) || "",
1040
+ accessLevelRemoteId: roleId,
1041
+ },
1042
+ });
1043
+ break;
1044
+ }
1045
+ case graphql_2.EntityType.Group: {
1046
+ requestedGroups.push({
1047
+ groupId: assetId,
1048
+ accessLevel: {
1049
+ accessLevelName: ((_d = (_c = assetNode.roles) === null || _c === void 0 ? void 0 : _c[roleId]) === null || _d === void 0 ? void 0 : _d.roleName) || "",
1050
+ accessLevelRemoteId: roleId,
1051
+ },
1052
+ });
1053
+ break;
1054
+ }
1055
+ }
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+ const resp = await createRequest(cmd, client, requestedResources, requestedGroups, metadata.reason, metadata.durationInMinutes);
1061
+ // Build link to request
1062
+ const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
1063
+ if (resp === null || resp === void 0 ? void 0 : resp.id) {
1064
+ cmd.log("\nšŸŽ‰ Your Access Request has been submitted!\n");
1065
+ cmd.log(`${chalk_1.default.bold("ID: ")} ${chalk_1.default.cyan(resp === null || resp === void 0 ? void 0 : resp.id)}`);
1066
+ if (resp === null || resp === void 0 ? void 0 : resp.status) {
1067
+ cmd.log((0, displays_1.getStyledStatus)(resp === null || resp === void 0 ? void 0 : resp.status));
1068
+ }
1069
+ const requestLink = `${configData[config_1.urlKey]}/requests/sent/${resp === null || resp === void 0 ? void 0 : resp.id}`;
1070
+ cmd.log(`${chalk_1.default.bold("Link:")} ${chalk_1.default.underline(requestLink)}\n`);
1071
+ }
1072
+ return;
1073
+ }
1074
+ async function bypassRequestSelection(cmd, client, flagValue, metadata) {
1075
+ var _a, _b;
1076
+ try {
1077
+ // Query Catalog Item endpoint to identify what the id belongs to (resource or group)
1078
+ for (const id of flagValue) {
1079
+ const resp = await client.query({
1080
+ query: CATALOG_ITEM,
1081
+ variables: {
1082
+ uuid: id || "",
1083
+ },
1084
+ fetchPolicy: "network-only", // to avoid caching
1085
+ });
1086
+ switch (resp.data.catalogItem.__typename) {
1087
+ case "Resource": {
1088
+ const resourceName = resp.data.catalogItem.displayName;
1089
+ const roles = (resp.data.catalogItem.accessLevels || [])
1090
+ // TODO: Support okta azure apps ?.filter((role) => role.accessLevelName !== "") // This assumes length == 1
1091
+ .map((role) => ({
1092
+ id: role.accessLevelRemoteId,
1093
+ name: role.accessLevelName,
1094
+ }));
1095
+ if (roles.length > 0 &&
1096
+ !(roles.length === 1 && roles[0].name === "")) {
1097
+ cmd.log(`Roles not implemented yet for resource ${resourceName}. Skipping roles selection.`); //TODO: Implement roles support
1098
+ continue;
1099
+ }
1100
+ const appId = ((_a = resp.data.catalogItem.connection) === null || _a === void 0 ? void 0 : _a.id) || "";
1101
+ if (!(appId in metadata.requestMap)) {
1102
+ metadata.requestMap[appId] = {
1103
+ appName: ((_b = resp.data.catalogItem.connection) === null || _b === void 0 ? void 0 : _b.displayName) || "",
1104
+ appId: appId,
1105
+ assets: {},
1106
+ };
1107
+ }
1108
+ const assetEntry = metadata.requestMap[appId].assets[id];
1109
+ if (!assetEntry) {
1110
+ metadata.requestMap[appId].assets[id] = {
1111
+ assetId: id,
1112
+ assetName: resourceName,
1113
+ type: graphql_2.EntityType.Resource,
1114
+ roles: {},
1115
+ };
1116
+ }
1117
+ if (roles && !(roles.length === 1 && roles[0].name === "")) {
1118
+ if (!metadata.requestMap[appId].assets[id].roles) {
1119
+ metadata.requestMap[appId].assets[id].roles = {};
1120
+ }
1121
+ for (const role of roles) {
1122
+ metadata.requestMap[appId].assets[id].roles[role.id] = {
1123
+ roleId: role.id,
1124
+ roleName: role.name,
1125
+ };
1126
+ }
1127
+ }
1128
+ break;
1129
+ }
1130
+ case "Group": {
1131
+ //TODO
1132
+ break;
1133
+ }
1134
+ case "Connection": {
1135
+ //TODO
1136
+ break;
1137
+ }
1138
+ default:
1139
+ cmd.error("Unknown error occurred.");
1140
+ }
1141
+ }
1142
+ }
1143
+ catch (error) {
1144
+ if (error instanceof Error || typeof error === "string") {
1145
+ cmd.error(error);
1146
+ }
1147
+ }
1148
+ return;
1149
+ }
1150
+ function bypassDuration(cmd, duration, metadata) {
1151
+ const maxDuration = metadata.requestDefaults.maxDurationInMinutes;
1152
+ if (maxDuration && duration > maxDuration) {
1153
+ cmd.error(`The requested duration exceeds the allowed limit of ${maxDuration}`);
1154
+ }
1155
+ metadata.durationInMinutes = duration;
1156
+ }
@@ -28,12 +28,17 @@ function treeifyRequestMap(cmd, requestMap) {
28
28
  for (const [_appId, appNode] of Object.entries(requestMap)) {
29
29
  const assetsTree = {};
30
30
  for (const [_assetId, assetNode] of Object.entries(appNode.assets)) {
31
- const assetKey = `${assetNode.assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
31
+ // If okta/azure asset with no role, change asset name
32
+ const assetName = assetNode.assetName || "No Role (Direct access)";
33
+ const assetKey = `${assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
32
34
  if (assetNode.roles !== undefined) {
33
35
  assetsTree[assetKey] = {};
34
36
  for (const [_roleId, roleNode] of Object.entries(assetNode.roles)) {
35
- const roleKey = `${roleNode.roleName} ${chalk_1.default.dim("[Role]")}`;
36
- assetsTree[assetKey][roleKey] = null;
37
+ const roleName = roleNode.roleName;
38
+ if (roleName !== "") {
39
+ const roleKey = `${roleName} ${chalk_1.default.dim("[Role]")}`;
40
+ assetsTree[assetKey][roleKey] = null;
41
+ }
37
42
  }
38
43
  }
39
44
  else {