Name
sn_grc.IssueUtilsBase
Description
Utilities for generating issues
Script
var IssueUtilsBase = Class.create();
IssueUtilsBase.prototype = {
initialize: function() {},
findExistingOpenIssue: function(item) {
return this._findExistingOpenIssue(item);
},
getIssueSource: function(issueSource) {
return this._getIssueSource(issueSource);
},
generateIssue: function(fields, issueSource) {
return this._generateIssue(fields, issueSource);
},
updateOrCreateIssue: function(item, issueSource) {
return this._updateOrCreateIssue(item, issueSource);
},
updateOrCreateIndicatorIssue: function(indicatorResult) {
return this._updateOrCreateIndicatorIssue(indicatorResult);
},
removeSourceOrCloseIndicatorIssue: function(indicatorResult) {
return this._removeSourceOrCloseIndicatorIssue(indicatorResult);
},
updateOrCreateControlTestIssue: function(controlTest) {
return this._updateOrCreateControlTestIssue(controlTest);
},
removeSourceOrCloseControlTestIssue: function(control) {
return this._removeSourceOrCloseControlTestIssue(control);
},
updateOrCreateAttestationIssue: function(control) {
return this._updateOrCreateAttestationIssue(control);
},
removeSourceOrCloseAttestationIssue: function(control) {
return this._removeSourceOrCloseAttestationIssue(control);
},
updateIsOriginatorForM2mRecords: function() {
return this._updateIsOriginatorForM2mRecords();
},
getAllIssuesWithEngagementsAssignedToMe: function() {
return this._getAllIssuesWithEngagementsAssignedToMe();
},
itemHasOpenIssues: function(itemId) {
return this._itemHasOpenIssues(itemId);
},
getMyIssues: function() {
return this._getMyIssues();
},
getIssueManagerGroupRoles: function() {
return 'roles=sn_grc.user^ORroles=sn_compliance.user^ORroles=sn_risk.user^ORroles=sn_audit.user^ORroles=sn_audit.manager^ORroles=sn_compliance.manager^ORroles=sn_risk.manager^ORroles=sn_grc.manager^EQ';
},
hasIssueManagerAccess: function() {
var hasIssueManagerAccess = (gs.getUser().hasRole('sn_grc.user'));
return hasIssueManagerAccess;
},
hasIssueAccess: function(current) {
var currentUserId = gs.getUserID();
var hasIssueAccess = gs.hasRole("sn_grc.user") ||
(!current.assignment_group.nil() && gs.getUser().isMemberOf(current.assignment_group + '')) || (current.assigned_to == currentUserId) ||
(!current.issue_manager_group.nil() && gs.getUser().isMemberOf(current.issue_manager_group + '')) || (current.issue_manager == currentUserId) ||
(this._isCurrentUserItemOwner(current, currentUserId)) || current.opened_by == gs.getUserID() ||
(GlidePluginManager.isActive('com.sn_grc_advanced') && gs.hasRole("sn_grc_advanced.issue_triage_user"));
if (hasIssueAccess) {
return hasIssueAccess;
} else {
hasIssueAccess = this.hasParentIssueAccess(current) || this.hasChildIssueAccess(current);
}
return hasIssueAccess;
},
_isCurrentUserItemOwner: function(issueGr, currentUserId) {
var sysIds = [];
var m2m = new GlideRecord("sn_grc_m2m_issue_item");
m2m.addQuery("sn_grc_issue", issueGr.getUniqueValue());
m2m.addQuery("sn_grc_item.owner", currentUserId);
m2m.setLimit(1);
m2m.query();
if (m2m.hasNext())
return true;
return false;
},
hasMyReportedIssuesAccess: function() {
return ((GlidePluginManager.isActive('com.sn_grc_advanced') && gs.getProperty("sn_grc_advanced.enable_my_issues_hide_my_reported_issues") == 'false') || !GlidePluginManager.isActive('com.sn_grc_advanced')) && (gs.hasRole('sn_grc.business_user') || gs.hasRole('sn_grc.business_user_lite'));
},
hasParentIssueAccess: function(current) {
var canAccessParentIssue = false;
var remTasks = new GlideAggregate("sn_grc_task");
remTasks.addQuery("issue", current.getUniqueValue());
remTasks.addEncodedQuery("assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe^ORwatch_listDYNAMIC90d1921e5f510100a9ad2572f2b477fe");
remTasks.addAggregate('COUNT');
remTasks.query();
if (remTasks.next()) {
canAccessParentIssue = remTasks.getAggregate('COUNT') != "0";
}
return canAccessParentIssue;
},
hasChildIssueAccess: function(current) {
var canAccessChildIssue = false;
canAccessChildIssue = (current.parent_issue.assigned_to == gs.getUserID()) ||
(!current.parent_issue.assignment_group.nil() && gs.getUser().isMemberOf(current.parent_issue.assignment_group + ''));
return canAccessChildIssue;
},
getEntity: function(itemId) {
var result = {};
var item = new GlideRecord('sn_grc_item');
item.get(itemId);
if (item.sys_class_name == 'sn_compliance_control')
item = new GlideRecord('sn_compliance_control');
else
item = new GlideRecord('sn_risk_risk');
if (item.get(itemId)) {
result['profile'] = item.profile + '';
}
return result;
},
_itemHasOpenIssues: function(itemId) {
var m2mIssueItem = new GlideRecord('sn_grc_m2m_issue_item');
m2mIssueItem.addQuery('sn_grc_item', itemId);
m2mIssueItem.addQuery('sn_grc_issue.active', true);
m2mIssueItem.setLimit(1);
m2mIssueItem.query();
return m2mIssueItem.hasNext();
},
_getIssueSource: function(issueSource) {
var source = new GlideRecord('sn_grc_choice');
source.addQuery('set', 'issue_source');
source.addQuery('name', issueSource);
source.query();
if (source.next()) {
return source;
} else {
return null;
}
},
//add issue source to issue if it doesn't exist already
_addIssueSource: function(issue, issueSource, comment) {
var issueSourceRec = this._getIssueSource(issueSource);
if (issueSourceRec) {
issueSourceID = issueSourceRec.getUniqueValue();
if (issue.issue_source.nil()) {
issue.issue_source = issueSourceID;
} else {
var issueSourceList = issue.issue_source.split(',');
if (issueSourceList.indexOf(issueSourceID) < 0) {
issueSourceList.push(issueSourceID);
issue.issue_source = issueSourceList.join(',');
}
}
if (comment) {
issue.comments = comment;
}
issue.update();
} else {
gs.getMessage('Cannot find Issue Source {0} on sn_grc_choice table', [issueSource]);
}
},
//remove issue source from control test issue, close issue if all sources are removed.
_removeSourceOrCloseControlTestIssue: function(issue) {
var issueSource = 'control_test';
var issueSourceRec = this._getIssueSource(issueSource);
issueSourceID = issueSourceRec.getUniqueValue();
if (issue.issue_source == issueSourceID) {
var msg = gs.getMessage('Issue automatically closed because Control test passed');
issue.state = '3';
issue.response = '1';
issue.issue_source = '';
issue.explanation = msg;
issue.comments = msg;
issue.update();
} else {
var issueList = issue.issue_source.split(',');
var index = issueList.indexOf(issueSourceID);
if (index > -1) {
issueList.splice(index, 1);
issue.issue_source = issueList.join(',');
issue.comments = gs.getMessage('Control test passed');
issue.update();
}
}
},
//remove issue source from attestation issue, close issue if all sources are removed.
_removeSourceOrCloseAttestationIssue: function(control) {
var issueSource = 'attestation';
var issueSourceRec = this._getIssueSource(issueSource);
issueSourceID = issueSourceRec.getUniqueValue();
var issue = new GlideRecord('sn_grc_issue');
issue.addQuery('item', control.getUniqueValue());
issue.addQuery('issue_source', 'CONTAINS', issueSourceID);
issue.addQuery('active', true);
issue.query();
while (issue.next()) {
if (issue.issue_source == issueSourceID) {
var msg = gs.getMessage('Issue automatically closed because Attestation passed');
issue.state = '3';
issue.response = '1';
issue.issue_source = '';
issue.explanation = msg;
issue.comments = msg;
issue.update();
} else {
var issueList = issue.issue_source.split(',');
var index = issueList.indexOf(issueSourceID);
if (index > -1) {
issueList.splice(index, 1);
issue.issue_source = issueList.join(',');
issue.comments = gs.getMessage('Attestation passed');
issue.update();
}
}
}
},
//remove source from indicator issue, close issue if all source are removed and auto close property is true
_removeSourceOrCloseIndicatorIssue: function(indicatorResult) {
var indicator = new GlideRecord('sn_grc_indicator');
indicator.get(indicatorResult.getValue('indicator'));
var sourceVulResponseRec = this._getIssueSource('vul_response');
var indicatorType = indicator.getValue('type');
var indicatorSource = indicator.getValue('issue_source');
//init issueSourceID and issue source as indicator
var issueSourceRec = this._getIssueSource('indicator');
var issueSource = 'indicator';
//check if indicator is config_test, set issue source as config_test
if (indicatorType == 'config_test') {
issueSource = 'config_test';
issueSourceRec = this._getIssueSource('config_test');
}
//check if indicator is vul response, set issue source as vul response
else if (sourceVulResponseRec && indicatorSource == sourceVulResponseRec.getUniqueValue()) {
issueSource = 'vul_response';
issueSourceRec = sourceVulResponseRec;
}
var issueSourceID = issueSourceRec.getUniqueValue();
//if source is Indicator, check indicator auto close property before closing issue, for all other indicator, auto close issue
if (gs.getProperty('sn_grc.auto_indicator_issue_closure') == 'true' || issueSource != 'indicator') {
//find all issues for this indicator failure
var indResult = new GlideAggregate('sn_grc_indicator_result');
indResult.addNotNullQuery('issue');
indResult.addQuery('indicator', indicator.getUniqueValue());
indResult.addQuery('issue.active', true);
indResult.addQuery('issue.issue_source', 'CONTAINS', issueSourceID);
indResult.addAggregate('COUNT', 'issue');
indResult.query();
while (indResult.next()) {
// check if issue is related to other indicator failure of same type
var issueID = indResult.issue.toString();
var issue = new GlideRecord('sn_grc_issue');
issue.get(issueID);
var otherIndicatorFailure = new GlideAggregate('sn_grc_indicator_result');
otherIndicatorFailure.addQuery('issue', issueID);
otherIndicatorFailure.addQuery('indicator', '!=', indicator.getUniqueValue());
otherIndicatorFailure.addQuery('indicator.last_result_passed', false);
otherIndicatorFailure.addQuery('indicator.type', indicator.getValue('type'));
if (issueSource == 'vul_response') {
otherIndicatorFailure.addQuery('indicator.issue_source', issueSourceID);
}
otherIndicatorFailure.query();
// don't change issue if there is failure from other indicator of same type
if (!otherIndicatorFailure.next()) {
//close issue if all issue source has been removed
if (issue.issue_source == issueSourceID) {
var msg = gs.getMessage('Issue automatically closed because the indicator {0} passed', [indicator.getValue('name')]);
issue.state = '3';
issue.response = '1';
issue.issue_source = '';
if (issueSource == 'vul_response') {
msg = gs.getMessage('This issue is related to indicator {0} and is auto closed based on resolution from the Vulnerability Management team', [indicator.getValue('name')]);
}
issue.explanation = msg;
issue.comments = msg;
issue.update();
} else {
//remove issue source if there are other source of failure
var issueList = issue.issue_source.split(',');
var index = issueList.indexOf(issueSourceID);
if (index > -1) {
issueList.splice(index, 1);
issue.issue_source = issueList.join(',');
issue.comments = gs.getMessage('indicator {0} passed', [indicator.getValue('name')]);
issue.update();
}
}
} else {
issue.comments = gs.getMessage('indicator {0} passed', [indicator.getValue('name')]);
issue.update();
}
}
}
},
_updateOrCreateAttestationIssue: function(control) {
var issueSource = 'attestation';
var issueComment = '';
var existingIssue = this._findExistingOpenIssue(control.getUniqueValue());
if (existingIssue) {
if (control.profile) {
issueComment = gs.getMessage('{0} has assessment failure on control {1}', [control.profile.name.toString(), control.getValue('name')]);
} else {
issueComment = gs.getMessage('There is an assessment failure on control {0}', [control.getValue('name')]);
}
this._addIssueSource(existingIssue, issueSource, issueComment);
} else {
var issue = {};
if (control.profile) {
issue.short_description = gs.getMessage('{0} has an assessment failure', control.profile.name.toString());
issue.description = gs.getMessage('{0} has an assessment failure on control {1}', [control.profile.name.toString(), control.getValue('name')]);
} else {
issue.short_description = gs.getMessage('Assessment failure on control {0}', [control.getValue('name')]);
issue.description = gs.getMessage('There is an assessment failure on control {0}', [control.getValue('name')]);
}
issue.item = control.getUniqueValue();
issue.assignment_group = control.getValue('owning_group');
issue.assigned_to = control.getValue('owner');
issue.profile = control.getValue('profile');
issue.created_manually = false;
var newIssue = this._generateIssue(issue, issueSource);
if (!newIssue) {
gs.addErrorMessage(gs.getMessage('Unable to create a issue for {0}', indicatorResult.indicator.number.toString()));
} else {
this._updateIsOriginatorForM2mRecord(issue.item, newIssue);
}
}
},
_updateOrCreateIndicatorIssue: function(indicatorResult) {
var issue = {};
var sourceVulResponse = this._getIssueSource('vul_response');
var item = new GlideRecord('sn_grc_item');
item.get(indicatorResult.indicator.item.toString());
var indicatorType = indicatorResult.indicator.type.toString();
var issueSource = 'indicator';
if (indicatorType == 'config_test') {
issueSource = 'config_test';
} else if (sourceVulResponse && indicatorResult.indicator.issue_source.toString() == sourceVulResponse.getUniqueValue()) {
issueSource = 'vul_response';
}
var existingIssue = this._findExistingOpenIssue(item.getUniqueValue());
if (existingIssue) {
var issueComment = '';
if (item.profile) {
issueComment = gs.getMessage('{0} has an indicator failure on {1}', [item.profile.name.toString(), item.getValue('name')]);
} else {
issueComment = gs.getMessage('There is has an indicator failure on {0}', item.getValue('name'));
}
this._addIssueSource(existingIssue, issueSource, issueComment);
indicatorResult.issue = existingIssue.getUniqueValue();
} else {
if (item.profile) {
issue.short_description = gs.getMessage('{0} has an indicator failure', item.profile.name.toString());
issue.description = gs.getMessage('{0} has an indicator failure on {1}', [item.profile.name.toString(), item.getValue('name')]);
} else {
issue.short_description = gs.getMessage('{0} has an indicator failure', [item.getValue('name')]);
issue.description = gs.getMessage('There is an indicator failure on {0}', [item.getValue('name')]);
}
issue.item = item.getUniqueValue();
issue.assignment_group = item.getValue('owning_group');
issue.assigned_to = item.getValue('owner');
//assign to profile owner if related to Vulnerability Response
if (issueSource == 'vul_response' && item.profile) {
issue.assigned_to = item.profile.owned_by.toString();
issue.assignment_group = '';
}
issue.profile = item.getValue('profile');
issue.created_manually = false;
var newIssue = this._generateIssue(issue, issueSource);
if (newIssue) {
this._updateIsOriginatorForM2mRecord(issue.item, newIssue);
indicatorResult.issue = newIssue;
} else {
gs.addErrorMessage(gs.getMessage('Unable to create a issue for {0}', indicatorResult.indicator.number.toString()));
}
}
},
_updateOrCreateControlTestIssue: function(controlTest) {
var issue = {};
var issueSource = "control_test";
issue.assignment_group = controlTest.getValue('assignment_group');
issue.assigned_to = controlTest.getValue('assigned_to');
issue.parent = controlTest.getUniqueValue();
issue.created_manually = false;
var control = new GlideRecord('sn_compliance_control');
//create new issue if test has no control or compliance is not installed or control is invalid
if (!controlTest.control || !control.isValid() || !control.get(controlTest.getValue('control'))) {
issue.short_description = gs.getMessage('Control test {0}: {1} fails', [controlTest.getValue('number'), controlTest.getValue('short_description')]);
issue.description = gs.getMessage('Control test {0}: {1} fails', [controlTest.getValue('number'), controlTest.getValue('short_description')]);
var newIssueNoControl = this._generateIssue(issue, issueSource);
if (newIssueNoControl) {
controlTest.issue = newIssueNoControl;
} else {
gs.addErrorMessage(gs.getMessage('Unable to create a issue for {0}', current.getValue('number')));
}
} else {
//create issue if control exist
var existingIssue = this._findExistingOpenIssue(controlTest.getValue('control'));
var issueComment = '';
//update existing issue with issue source
if (existingIssue) {
if (control.profile) {
issueComment = gs.getMessage('{0} has control test failure on control {1}', [control.profile.name.toString(), control.getValue('name')]);
} else {
issueComment = gs.getMessage('There is a control test failure on control {0}', [control.getValue('name')]);
}
this._addIssueSource(existingIssue, issueSource, issueComment);
controlTest.issue = existingIssue.getUniqueValue();
//create new issue if can't find existing issue
} else {
if (control.profile) {
issue.short_description = gs.getMessage('{0} has a control test failure', control.profile.name.toString());
issue.description = gs.getMessage('{0} has control test failure on control {1}', [controlTest.control.profile.name.toString(), control.getValue('name')]);
issue.profile = control.getValue('profile');
} else {
issue.short_description = gs.getMessage('Control test failure on {0}', [control.getValue('name')]);
issue.description = gs.getMessage('There is a control test failure on control {0}', [control.getValue('name')]);
}
issue.item = control.getUniqueValue();
var newIssue = this._generateIssue(issue, issueSource);
if (newIssue) {
this._updateIsOriginatorForM2mRecord(issue.item, newIssue);
controlTest.issue = newIssue;
} else {
gs.addErrorMessage(gs.getMessage('Unable to create a issue for {0}', controlTest.getValue('number')));
}
}
}
controlTest.update();
},
_getAllIssuesWithEngagementsAssignedToMe: function() {
var issues = [];
var m2mIssueEngagement = new GlideAggregate("sn_grc_m2m_issue_engagement");
m2mIssueEngagement.addEncodedQuery("sn_audit_engagement.approversDYNAMIC90d1921e5f510100a9ad2572f2b477fe^ORsn_audit_engagement.auditorsDYNAMIC90d1921e5f510100a9ad2572f2b477fe^ORsn_audit_engagement.assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe");
m2mIssueEngagement.groupBy("sn_grc_issue");
m2mIssueEngagement.query();
while (m2mIssueEngagement.next()) {
issues.push(m2mIssueEngagement.getValue("sn_grc_issue"));
}
return issues.join(',');
},
_findExistingOpenIssue: function(item) {
var issuesToItemM2M = new GlideRecord("sn_grc_m2m_issue_item");
issuesToItemM2M.addQuery("sn_grc_item", item);
issuesToItemM2M.orderByDesc("sn_grc_issue.sys_created_on");
issuesToItemM2M.addQuery('sn_grc_issue.active=true^is_originator=true^sn_grc_issue.created_manually=false');
issuesToItemM2M.query();
if (issuesToItemM2M.next()) {
var issueRec = new GlideRecord("sn_grc_issue");
issueRec.get(issuesToItemM2M.getValue('sn_grc_issue'));
return issueRec;
}
return null;
},
_generateIssue: function(fields, issueSource) {
var issue = new GlideRecord("sn_grc_issue");
for (var key in fields) {
if (issue.getElement(key) != null) issue.setValue(key, fields[key]);
}
if (issueSource) {
var source = this._getIssueSource(issueSource);
if (source) {
issue.issue_source = source.getUniqueValue();
}
}
return issue.insert();
},
_updateIsOriginatorForM2mRecord: function(item, issue) {
var m2mIssueItem = new GlideRecord("sn_grc_m2m_issue_item");
m2mIssueItem.addQuery("sn_grc_item", item);
m2mIssueItem.addQuery("sn_grc_issue", issue);
m2mIssueItem.query();
if (m2mIssueItem.next()) {
m2mIssueItem.setValue("is_originator", true);
m2mIssueItem.update();
}
},
_updateIsOriginatorForM2mRecords: function() {
var m2m = new GlideRecord("sn_grc_m2m_issue_item");
m2m.addQuery("sn_grc_item.sys_class_name", "sn_compliance_control");
m2m.addQuery("sn_grc_issue.created_manually", false);
m2m.setValue("is_originator", true);
m2m.setWorkflow(false);
m2m.updateMultiple();
},
_updateOrCreateIssue: function(item, issueSource) {
var existingIssue = this.findExistingOpenIssue(item.getUniqueValue());
if (existingIssue != null) {
var issueComment = gs.getMessage('{0} has an indicator failure on {1}', [item.profile.name.toString(), item.getValue('name')]);
this._addIssueSource(existingIssue, issueSource, issueComment);
return existingIssue.getUniqueValue();
} else {
var issue = {};
issue.short_description = gs.getMessage('{0} has an indicator failure', item.profile.name.toString());
issue.description = gs.getMessage('{0} has an indicator failure on {1}', [item.profile.name.toString(), item.getValue('name')]);
issue.item = item.getUniqueValue();
issue.assignment_group = item.getValue('owning_group');
issue.assigned_to = item.getValue('owner');
issue.profile = item.getUniqueValue();
issue.created_manually = false;
var newIssueID = this._generateIssue(issue, issueSource);
if (!newIssueID) {
gs.addErrorMessage(gs.getMessage('Unable to create a issue for {0}', indicatorResult.indicator.number.toString()));
} else {
return newIssueID;
}
}
},
_getMyIssues: function() {
var gr = new GlideRecordSecure('sn_grc_issue');
gr.addQuery('opened_by', gs.getUserID());
gr.orderByDesc('sys_created_on');
gr.query();
var myIssues = [];
while (gr.next()) {
var iss = {};
iss.sys_id = gr.getUniqueValue() + '';
iss.number = gr.number + '';
iss.profile = gr.getDisplayValue('profile') + '';
iss.content = gr.getDisplayValue('content') + '';
iss.state = gr.getDisplayValue('state');
myIssues.push(iss);
}
return myIssues;
},
_isIssueManagerOrGroup: function(userId) {
var isIssueManagerOrGroup = (current.issue_manager_group && (gs.getUser().isMemberOf(current.issue_manager_group + ''))) ||
(userId == current.issue_manager + '');
return isIssueManagerOrGroup;
},
sendInformation: function(recordId, comments) {
var issueRecord = new GlideRecord('sn_grc_issue');
if (!issueRecord.get(recordId))
return false;
issueRecord.substate = '2';
issueRecord.comments = comments;
if (!issueRecord.update())
return false;
return true;
},
requestInformation: function(sysId, comments) {
var isUpdated = false;
var issueRecord = new GlideRecord('sn_grc_issue');
if (issueRecord.get(sysId)) {
issueRecord.comments = comments;
issueRecord.substate = '1';
issueRecord.update();
isUpdated = true;
}
return isUpdated;
},
getControlRiskClass: function(itemId, itemId_old) {
var result = {};
var item = new GlideRecord('sn_grc_item');
if (item.get(itemId)) {
result['class_type'] = item.sys_class_name + '';
}
item = new GlideRecord('sn_grc_item');
if (item.get(itemId_old)) {
result['class_type_old'] = item.sys_class_name + '';
}
return result;
},
getContent: function(itemId) {
var result = {};
var item = new GlideRecord('sn_grc_item');
if (item.canRead() && item.get(itemId)) {
result['content'] = item.content + '';
}
return result;
},
type: 'IssueUtilsBase'
};
Sys ID
9a50f644d7011200d77c83e80e6103fa