Name

sn_grc.ImportProfilesBase

Description

Library to import profiles into GRC

Script

var ImportProfilesBase = Class.create();
ImportProfilesBase.prototype = {
  initialize: function() {},
  getHierarchy: function(currentId, direction, tableName, category) {
      return this._getHierarchy(null, currentId, direction, tableName, category);
  },
  hasParent: function(processId) {
      return this._hasParent(processId);
  },
  hasUpstreamStagedProfiles: function(stagedProfileId) {
      return this._hasUpstreamStagedProfiles(stagedProfileId);
  },
  createProfilesAndRelationships: function(rootId) {
      return this._createProfilesAndRelationships(rootId);
  },
  clearStagedProfilesAndRelationships: function(rootId) {
      return this._clearStagedProfilesAndRelationships(rootId);
  },
  getProfileClass: function(tableName, recordId) {
      return this._getProfileClass(tableName, recordId);
  },
  isValidHierarchy: function(current) {
      return this._isValidHierarchy(current);
  },
  isProfileRelationshipAvailable: function(profileId, profileRelationship) {
      return this._isProfileRelationshipAvailable(profileId, profileRelationship);
  },
  getCategories: function(profile, direction) {
      return this._getCategories(profile, direction);
  },
  getInvalidProfiles: function(profile, direction) {
      return this._getInvalidProfiles(profile, direction);
  },
  generateProfiles: function() {
      if (this._isEntityScopingEnabledForCMDBQuery()) {
          gs.eventQueue('sn_grc.generate_profiles_from_job', null);
      } else {
          this._generateProfiles();
      }
  },
  createProfile: function(params) {
  	return this._createProfile(params);
  },
  getProfileById: function(source) {
  	return this._getProfileById(source);
  },
  isEntityScopingEnabledForCMDBQuery: function() {
      return this._isEntityScopingEnabledForCMDBQuery();
  },
  _isEntityScopingEnabledForCMDBQuery: function() {
      var isPropertyEnabled = gs.getProperty('sn_grc.enable_entity_scoping_for_cmdb_query', '');
      if (isPropertyEnabled == 'true') {
          var sysId = 'b957ed9b0720301054685d3f0ad3006d';
          var grScriptInclude = new GlideRecord('sys_script_include');
          return grScriptInclude.get(sysId);
      }

      return false;
  },
  generateProfilesFromEvent: function() {
      this._generateProfiles();
  },
  _generateProfiles: function() {
      var deleteRecordsList = [];
      var profileTypeSysIds = [];
      var profileType = new GlideRecord('sn_grc_profile_type');
      profileType.addActiveQuery();
      profileType.addQuery("processing_profiles", false);
      profileType.query();
      while (profileType.next()) {
          profileType.setValue("processing_profiles", true);
          profileType.update();
          var unwantedRecordsList = [];
          var profileTypeId = profileType.getUniqueValue();
          unwantedRecordsList = new GRCUtils().generateProfilesJob(profileType, false);
          if (unwantedRecordsList.length != 0) {
              profileTypeSysIds.push(profileTypeId);
              deleteRecordsList = deleteRecordsList.concat(unwantedRecordsList);
          }
      }
      if (deleteRecordsList.length > 0) {
          //Remove unwanted m2m records
          var util = new ItemGenerationV2Conditions();
          var grUnwanted = new GlideRecord('sn_grc_m2m_profile_profile_type');
          grUnwanted.addQuery("sys_id", "IN", deleteRecordsList);
          grUnwanted.query();
          while (grUnwanted.next()) {
              var entityTypeId = grUnwanted.getValue('profile_type');
              var entityId = grUnwanted.getValue('profile');
              grUnwanted.skipInsertActionToQueue = true;
              grUnwanted.deleteRecord();
              if (util.entityTypeHasActiveContentAssociation(entityTypeId) || util.entityTypeHasItemAssociation(entityTypeId, false) ) {
                  var actionParms = {
                      action: 'remove_entity_from_entity_type',
                      entity_type_id: entityTypeId,
                      entity_id: entityId,
                  };
                  new sn_grc.IGEntityToEntityTypeActionHandler(actionParms).execute();
              }
          }
      }
      //sets processing_profiles to false for profile types 
      var profileTypes = new GlideRecord("sn_grc_profile_type");
      profileTypes.addQuery("sys_id", "IN", profileTypeSysIds);
      profileTypes.setValue("processing_profiles", false);
      profileTypes.updateMultiple();
      var psToRs = new GlideRecord("sn_risk_m2m_risk_definition_policy_statement");
      if (psToRs.isValid()) {
          psToRs.addQuery("last_associated_timestamp", "!=", "");
          psToRs.query();
          while (psToRs.next()) {
              var psToRsActionParms = {
                  action: 'add_content_to_content',
                  table: 'sn_risk_m2m_risk_definition_policy_statement',
                  source: psToRs.getUniqueValue(),
                  content_id: psToRs.getValue('sn_risk_definition')
              };
              var strategy = new ItemGenerationV2Utils().getStrategy('sn_risk');
              new IGContentActionHandler(psToRsActionParms, strategy).execute();
          }
      }
  },
  _getInvalidProfiles: function(profile, direction) {
      // This function is looking for the profile already associated in the opposite direction
      // and which are also presents in the direction we are looking for in order to avoid loops
      var invalidProfileIds = [];
      invalidProfileIds.push(profile.sys_id + '');
      var oppositeDirection = direction == 'upstream' ? 'downstream' : 'upstream';
      var associatedProfileIds = this._getAssociatedProfiles(profile.sys_id + '', oppositeDirection);
      var categoryIds = this._getCategories(profile, direction);
      var possibleInvalidRelations = new GlideRecord('sn_grc_profile');
      possibleInvalidRelations.addQuery("profile_class.category", "IN", categoryIds).addOrCondition("profile_class.category", "");
      possibleInvalidRelations.addQuery('sys_id', 'IN', associatedProfileIds);
      possibleInvalidRelations.query();
      while (possibleInvalidRelations.next())
          invalidProfileIds.push(possibleInvalidRelations.sys_id + '');
      return invalidProfileIds;
  },
  _isProfileRelationshipAvailable: function(profileId, profileRelationship) {
      var profile = new GlideRecord("sn_grc_profile");
      if (profile.get(profileId)) {
          var direction = "downstream";
          if (profileRelationship.getEncodedQuery().indexOf("downstream_profile=" + profileId) != -1)
              direction = "upstream";
          var categoryIds = new sn_grc.ImportProfiles().getCategories(profile, direction);
          var invalidIds = new sn_grc.ImportProfiles().getInvalidProfiles(profile, direction);
          var eligibleProfiles = new GlideRecord("sn_grc_profile");
          eligibleProfiles.addEncodedQuery("active=true^profile_class.categoryIN" + categoryIds + "^ORprofile_class.category=^sys_idNOT IN" + invalidIds);
          eligibleProfiles.query();
          var eligibleProfileList = [];
          while (eligibleProfiles.next())
              eligibleProfileList.push(eligibleProfiles.sys_id + '');
          var oppositeDirection = (direction == "upstream") ? "downstream" : "upstream";
          for (var i = 0; i < eligibleProfileList.length; i++) {
              var m2m = new GlideRecord("sn_grc_m2m_profile_profile");
              m2m.addQuery(oppositeDirection + "_profile", profileId + '');
              m2m.addQuery(direction + "_profile", eligibleProfileList[i] + '');
              m2m.setLimit(1);
              m2m.query();
              if (!m2m.hasNext())
                  return true;
          }
      }
      return false;
  },
  _getCategories: function(profile, direction) {
      var category = new GlideRecord("sn_grc_profile_tier");
      var profileCategory = new GlideRecord("sn_grc_profile_tier");
      if (profileCategory.get(profile.profile_class.category)) {
          if (direction == "upstream") {
              category.addQuery("tier_level", "<=", profileCategory.tier_level);
              category.orderByDesc("tier_level");
          } else if (direction == "downstream") {
              category.addQuery("tier_level", ">=", profileCategory.tier_level);
              category.orderBy("tier_level");
          }
          category.setLimit(2);
      }
      category.query();
      var categoryIds = [];
      while (category.next())
          categoryIds.push(category.getUniqueValue() + '');
      return categoryIds;
  },
  getAssociatedProfiles: function(profileId, direction) {
      return this._getAssociatedProfiles(profileId, direction);
  },
  _getAssociatedProfiles: function(profileId, direction) {
      var profileM2M = new GlideRecord("sn_grc_m2m_profile_profile");
      if (direction == 'upstream')
          profileM2M.addQuery('downstream_profile', profileId);
      else if (direction == 'downstream')
          profileM2M.addQuery('upstream_profile', profileId);
      profileM2M.query();
      var profileIds = [];
      while (profileM2M.next())
          profileIds.push(profileM2M[direction + '_profile'] + '');
      return profileIds;
  },
  _isValidHierarchy: function(current) {
      var profiles = new sn_grc.GRCUtils().getMessage("profiles");
      var profile = new sn_grc.GRCUtils().getMessage("profile");
      var map = this._getCategoryMap();
      var isValidHierarchy = {
          errorMessage: '',
          value: true
      };
      if (current.upstream_profile + '' == current.downstream_profile + '') {
          isValidHierarchy.errorMessage = gs.getMessage("Invalid Relationship: Upstream {0} cannot be same as downstream {0}", profile);
          isValidHierarchy.value = false;
          return isValidHierarchy;
      }
      var upstreamCategory = current.upstream_profile.profile_class.category + '';
      var downstreamCategory = current.downstream_profile.profile_class.category + '';
      if (upstreamCategory != '' && downstreamCategory != '' && map[upstreamCategory].value > map[downstreamCategory].value) {
          isValidHierarchy.errorMessage = gs.getMessage('Invalid Relationship: {2} from {0} category cannot roll up to {1} category', [map[downstreamCategory].name, map[upstreamCategory].name, profiles]);
          isValidHierarchy.value = false;
          return isValidHierarchy;
      }
      var upstreamProfiles = new sn_grc.GRCProfileLists().getUpstreamProfiles(current.upstream_profile + '');
      if (upstreamProfiles.indexOf(current.downstream_profile + '') != -1) {
          isValidHierarchy.errorMessage = gs.getMessage("Invalid Relationship: {0} is already an upstream {2} to {1} and therefore cannot be selected as downstream {2}", [current.downstream_profile.name, current.upstream_profile.name, profile]);
          isValidHierarchy.value = false;
      }
      return isValidHierarchy;
  },
  _getCategoryMap: function() {
      var map = {};
      var category = new GlideRecord("sn_grc_profile_tier");
      category.query();
      while (category.next())
          map[category.getUniqueValue() + ''] = {
              name: category.label + '',
              value: parseInt(category.tier_level)
          };
      return map;
  },
  _hasParent: function(processId) {
      var rel = new GlideRecord('cmdb_rel_ci');
      rel.addQuery('child', processId);
      rel.query();
      if (rel.hasNext())
          return true;
      return false;
  },
  _hasUpstreamStagedProfiles: function(stagedProfileId) {
      var m2m = new GlideRecord('sn_grc_m2m_profile_staging');
      m2m.addQuery('downstream', stagedProfileId);
      m2m.query();
      if (m2m.hasNext())
          return true;
      return false;
  },
  _getHierarchy: function(parentId, currentId, direction, tableName, category) {
      var visitedItems = {};
      this.rootId = currentId;
      this.rootTable = tableName;
      if (category)
          this._getTablesFromCategory(category);
      this._getRelationship(visitedItems, parentId, currentId, direction, tableName);
  },
  _getTablesFromCategory: function(category) {
      var categoryId = "";
      var categoryRec = new GlideRecord("sn_grc_profile_tier");
      categoryRec.get("name", category);
      categoryId = categoryRec.getUniqueValue();
      if (!categoryId)
          return;
      var rule = new GlideRecord('sn_grc_profile_class_rules');
      rule.addQuery('profile_class.category', categoryId);
      rule.query();
      var tableNames = [];
      while (rule.next())
          tableNames.push(rule.table + '');
      this.tableNames = tableNames;
  },
  _getRelationship: function(visitedItems, parentId, currentId, direction, tableName) {
      if (!visitedItems[currentId])
          this._createStagedProfile(currentId, tableName);
      // create m2m staging
      this._createM2mStagedProfile(parentId, currentId, direction);
      if (visitedItems[currentId])
          return;
      // create staged profile
      visitedItems[currentId] = true;
      parentId = currentId;
      var rel = new GlideRecord('cmdb_rel_ci');
      if (direction == 'upstream')
          rel.addQuery('child', currentId);
      else
          rel.addQuery('parent', currentId);
      if (this.tableNames)
          rel.addQuery('child.sys_class_name', 'IN', this.tableNames);
      rel.query();
      while (rel.next()) {
          if (direction == 'upstream') {
              currentId = rel.parent + '';
              tableName = rel.parent.sys_class_name + '';
          } else {
              currentId = rel.child + '';
              tableName = rel.child.sys_class_name + '';
          }
          this._getRelationship(visitedItems, parentId, currentId, direction, tableName);
      }
  },
  _createStagedProfile: function(sourceId, tableName) {
      var source = new GlideRecord(tableName);
      if (!source.get(sourceId))
          return;
      // Check if the source already exists in the staging table
      var target = new GlideRecord('sn_grc_profile_staging');
      if (target.get('applies_to', sourceId))
          return;
      target.name = source.getDisplayValue();
      target.owned_by = source.assigned_to;
      target.table = tableName + '';
      target.applies_to = sourceId;
      target.root_id = this.rootId;
      target.root_table = this.rootTable;
      if (!target.insert())
          return;
  },
  _getStagedProfileById: function(sourceId) {
      if (sourceId == null)
          return null;
      var stagingProfile = new GlideRecord('sn_grc_profile_staging');
      if (!stagingProfile.get('applies_to', sourceId))
          return null;
      return stagingProfile.sys_id + '';
  },
  _createM2mStagedProfile: function(targetId, nextTargetId, direction) {
      var sourceStagingProfileId = this._getStagedProfileById(targetId);
      var targetStagingProfileId = this._getStagedProfileById(nextTargetId);
      if ((sourceStagingProfileId == null) || (targetStagingProfileId == null))
          return;
      var m2m = new GlideRecord('sn_grc_m2m_profile_staging');
      if (direction == 'upstream') {
          m2m.addQuery('upstream', targetStagingProfileId);
          m2m.addQuery('downstream', sourceStagingProfileId);
      } else {
          m2m.addQuery('downstream', targetStagingProfileId);
          m2m.addQuery('upstream', sourceStagingProfileId);
      }
      m2m.query();
      if (!m2m.next()) {
          m2m = new GlideRecord('sn_grc_m2m_profile_staging');
          if (direction == 'upstream') {
              m2m.upstream = targetStagingProfileId;
              m2m.downstream = sourceStagingProfileId;
          } else {
              m2m.downstream = targetStagingProfileId;
              m2m.upstream = sourceStagingProfileId;
          }
          m2m.insert();
      }
  },
  _cleanupProfiles: function(rootId) {
      var stagedProfile = new GlideRecord('sn_grc_profile_staging');
      stagedProfile.addQuery('root_id', rootId);
      stagedProfile.query();
      while (stagedProfile.next()) {
          var profile = new GlideRecord('sn_grc_profile');
          if (profile.get('applies_to', stagedProfile.applies_to + ''))
              profile.deleteRecord();
      }
  },
  _cleanupProfileRelationships: function(rootId) {
      var stagedM2m = new GlideRecord('sn_grc_m2m_profile_staging');
      stagedM2m.addQuery('downstream.root_id', rootId);
      stagedM2m.query();
      while (stagedM2m.next()) {
          var m2m = new GlideRecord('sn_grc_m2m_profile_profile');
          m2m.addQuery('upstream_profile.applies_to', stagedM2m.upstream.applies_to + '');
          m2m.addQuery('downstream_profile.applies_to', stagedM2m.downstream.applies_to + '');
          m2m.query();
          m2m.deleteMultiple();
      }
  },
  _createProfilesAndRelationships: function(rootId) {
      // Create profiles
      var stagedProfile = new GlideRecord('sn_grc_profile_staging');
      stagedProfile.addQuery('root_id', rootId);
      stagedProfile.query();
      while (stagedProfile.next()) {
          if (!this._createProfile(stagedProfile)) {
              // Clean up all the remaining profiles
              this._cleanupProfiles(rootId);
              gs.addErrorMessage(new sn_grc.GRCUtils().getMessage("profile_type_to_error_generation"));
              return false;
          }
      }
      // Create m2m relationship between profiles
      var m2m = new GlideRecord('sn_grc_m2m_profile_staging');
      m2m.addQuery('downstream.root_id', rootId);
      m2m.query();
      while (m2m.next()) {
          if (!this._createProfileRelationship(m2m)) {
              this._cleanupProfileRelationships(rootId);
              this._cleanupProfiles(rootId);
              gs.addErrorMessage(new sn_grc.GRCUtils().getMessage("profile_type_to_error_generation"));
              return false;
          }
      }
      gs.addInfoMessage(gs.getMessage('Import profile complete.'));
      return true;
  },
  _clearStagedProfilesAndRelationships: function(rootId) {
      var stagedProfile = new GlideRecord('sn_grc_profile_staging');
      stagedProfile.addQuery('root_id', rootId);
      stagedProfile.query();
      stagedProfile.deleteMultiple();
      var m2m = new GlideRecord('sn_grc_m2m_profile_staging');
      m2m.addQuery('downstream.root_id', rootId);
      m2m.query();
      m2m.deleteMultiple();
  },
  _getProfileById: function(sourceId) {
      if (sourceId == null)
          return null;
      var profile = new GlideRecord('sn_grc_profile');
      if (!profile.get('applies_to', sourceId))
          return null;
      return profile.sys_id + '';
  },
  _createProfileRelationship: function(m2m) {
      var upstream = this._getProfileById(m2m.upstream.applies_to + '');
      var downstream = this._getProfileById(m2m.downstream.applies_to + '');
      if (upstream == null || downstream == null)
          return false;
      var profileRel = new GlideRecord('sn_grc_m2m_profile_profile');
      profileRel.addQuery('upstream_profile', upstream);
      profileRel.addQuery('downstream_profile', downstream);
      profileRel.query();
      if (profileRel.next())
          return true;
      profileRel.initialize();
      profileRel.upstream_profile = upstream;
      profileRel.downstream_profile = downstream;
      if (!profileRel.insert()) {
          var pr = new sn_grc.GRCUtils().getMessage("profile_type_lower");
          gs.info(gs.getMessage("The {2} relationship creation failed for {0} and {1}", [m2m.upstream.getDisplayValue(), m2m.downstream.getDisplayValue(), pr]));
          return false;
      }
      return true;
  },
  _getProfileClass: function(tableName, recordId) {
      var profileClass = '';
      var rule = new GlideRecord('sn_grc_profile_class_rules');
      rule.addQuery('table', tableName);
      rule.setLimit(1);
      rule.query();
  	if (rule.next()) {
  		profileClass = rule.getValue("profile_class");
  		var subClass = this.getSubClassUsingClassRuleFilters(rule.getUniqueValue(), recordId, tableName);
  		if(subClass != "") {
  			return subClass;
  		}
      }
      return profileClass;
  },
  
  getSubClassUsingClassRuleFilters: function(profileClassRuleId, recordId, tableName) {
  	var filter = new GlideRecord('sn_grc_profile_class_rule_filter');
  	filter.addQuery('profile_class_rules', profileClassRuleId);
  	filter.query();
  	var subClass = "";
  	var priorityNo;
  	while(filter.next()) {
  		var isValid = this.checkIfRecordPartOfCurrentFilter(filter, tableName, recordId);
  		if(!isValid) {
  			continue;
  		}
  		var tempClass = filter.getValue('sub_class');
  		var currentFilterPriority = parseInt(filter.getValue('filter_priority'));
  		if(subClass=="" || priorityNo>currentFilterPriority) {
  			subClass = tempClass;
  			priorityNo = currentFilterPriority;
  		}
  	}
  	return subClass;
  },
  
  checkIfRecordPartOfCurrentFilter: function(filter, tableName, recordId) {
  	var condition = filter.getValue('condition');
  	if (condition == undefined) {
  		return true;
  	}
  	var gr = this.getTableRecords(tableName, condition);
  	while(gr.next()) {
  		if(gr.getUniqueValue() == recordId) {
  			return true;
  		}
  	}
  	return false;
  },
  
  getTableRecords: function(table, condition) {
      var gr = new GlideRecord(table);
      gr.initialize();
      if (!gs.nil(condition)) {
          gr.addEncodedQuery(condition);
      }
      gr.query();
      return gr;
  },
  
  
  _createProfile: function(source) {
      // Check if the source already exists in the staging table
      var target = new GlideRecord('sn_grc_profile');
      if (target.get('applies_to', source.applies_to + ''))
          return true;
      target.name = source.name;
      target.owned_by = source.owned_by;
      target.table = source.table;
      target.applies_to = source.applies_to;
      // Get class by table
      target.profile_class = this._getProfileClass(source.table + '', source.applies_to + '');
      if (!target.insert()) {
          var pr = new sn_grc.GRCUtils().getMessage("profile_type_lower");
          gs.info(gs.getMessage("The {1} creation failed for {0}", [source.name, pr]));
          return false;
      }
      return true;
  },
  type: 'ImportProfilesBase'
};

Sys ID

7d9f9769e7223200dd926217c2f6a9d3

Offical Documentation

Official Docs: