-
Bug
-
Resolution: Fixed
-
Medium
-
5.12.14
-
3
-
Severity 2 - Major
-
27
-
Issue Summary
Groovy script is not triggered via Assets Automation after upgrading JSM version to 5.12.14.
Steps to Reproduce
- Create the following automation in a scheme (the rule must be triggered by the current user)
- When - Object Updated
- If - Any objects
- Then -
- Action - Execute Groovy script
- File path - D:/Atlassian/Application Data/JIRA/scripts/Insight/insight-restore-attribute-value.groovy
Use the following code in the script
/* This script checks if changes were made by user who is able to edit specific attribute in Inisght. It protects from adding the wrong people as approvers in Release process. Updated PTC-4925: The script checks an update on Security approvers attribute and restore the previous value if the update was made by user that's not a schema manager. */ import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.security.groups.GroupManager import com.atlassian.jira.user.ApplicationUser import com.riadalabs.jira.plugins.insight.services.model.CommentBean import com.riadalabs.jira.plugins.insight.services.model.RoleBean import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeFacade import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ConfigureFacade interface scriptConfig { final GroupManager groupManager = ComponentAccessor.getGroupManager() final ApplicationUser svcScriptRunner = ComponentAccessor.getUserManager().getUserByName("svc.JIRA.ScriptRunne") // Service account final String firstApproverAttribute = "Domain Owner - First Approver" // First Approver attribute name final String approvalDelegateAttribute = "Domain - Release First Approval Delegate" // Release First Approval Delegate attribute name final String secApproversAttribute = "Security approvers" // Release First Approval Delegate attribute name final int domainDelegatesAttributeID = 479 // Id of Domain Delegates attribute which triggers the script final int securityApproversAttributeId = 866 // Id of Security Approvers attribute which triggers the script final String jiraAdminsGroup = "jira-administrators" // Name of group for Jira Admins final Integer commentRole = 0 // The ID of the role for which the comment is visible, 0 means comment is public final ObjectFacade objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade) final ObjectTypeFacade objectTypeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectTypeFacade) final ConfigureFacade configureFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ConfigureFacade) final int orgSchemeId = 1 final String managerSchemeRole = "Object Schema Managers" final String userRoleType = "atlassian-user-role-actor" final String groupRoleType= "atlassian-group-role-actor" } log.warn("Attribute restore START") main() log.warn("Attribute restore END") /* This main function returns old value in attribute if was edited by wrong person. */ void main(){ try { log.warn("objectUpdateList ${objectUpdateList}") log.warn("objectUpdateList available properties ${objectUpdateList.getProperties()}") objectUpdateList.each{ change -> if (change.getAttributeName() == scriptConfig.approvalDelegateAttribute){ restoreDomainDelegatesValue(change) } else if (change.getAttributeName() == scriptConfig.secApproversAttribute){ restoreSecurityApprovers(change) } } }catch(Exception e){ log.warn(e.toString()) log.warn(e.stackTrace.toString()) } } /** * Restores a previous value of the Domain Owner - First Approver attribute if it was updated by user that is not allowed to do it. * @param change */ void restoreDomainDelegatesValue(def change){ ApplicationUser user = ComponentAccessor.getUserManager().getUserByName(currentUser.getName()) log.warn(ComponentAccessor.getGroupManager().isUserInGroup(user, scriptConfig.jiraAdminsGroup).toString()) log.warn(isUserInJiraAdminGroup(user)) def isUserInJiraAdminGroup = isUserInJiraAdminGroup(user) boolean isUserDomainOwner = isUserDomainOwner(object,scriptConfig.firstApproverAttribute,user) boolean isUserSvcAccount = isUserSvcAccount(user) String message = "Dear $user.displayName, you are not allowed to edit ${scriptConfig.approvalDelegateAttribute} attribute." + "Please contact with ${scriptConfig.firstApproverAttribute} or Jira Admins." if (!isUserDomainOwner && !isUserSvcAccount && !isUserInJiraAdminGroup){ addCommentToObject(message,scriptConfig.svcScriptRunner,object,scriptConfig.commentRole) ArrayList<String> oldValue = change.getRemovedValues() as ArrayList updateAttributeInObject(object, oldValue, scriptConfig.domainDelegatesAttributeID) } else { log.warn("User changed ${change.getAttributeName()}") } } /** * Restores a previous value of the Security Approvers attribute if it was updated by user that is not allowed to do it. * @param change */ void restoreSecurityApprovers(def change){ ApplicationUser currentUser = currentUser as ApplicationUser boolean isUserInJiraAdminGroup = isUserInJiraAdminGroup(currentUser) boolean isUserSvcAccount = isUserSvcAccount(currentUser) boolean isUserSchemeManager = isUserMemberOfRole(currentUser, scriptConfig.managerSchemeRole) String message = "Dear $currentUser.displayName, you are not allowed to edit ${scriptConfig.secApproversAttribute} attribute." + "Please contact with scheme managers or Jira Admins." if (!isUserInJiraAdminGroup && !isUserSvcAccount && !isUserSchemeManager){ addCommentToObject(message,scriptConfig.svcScriptRunner,object,scriptConfig.commentRole) ArrayList<String> oldValue = change.getRemovedValues() as ArrayList updateAttributeInObject(object, oldValue, scriptConfig.securityApproversAttributeId) } else { log.warn("User changed ${change.getAttributeName()}") } } /** * * @param currentUser - User that made a change on an object * @param roleName - A roleName where the user must be added to return TRUE * @return TRUE / FALSE depends if the user is a particular group */ boolean isUserMemberOfRole(ApplicationUser currentUser, String roleName){ List<String> usersInRole = [] List<RoleBean> roles = scriptConfig.configureFacade.findRoleBeansByObjectSchema(scriptConfig.orgSchemeId) roles.each{ role -> if (role.name == roleName){ role.roleActorBeans.each{roleActorBean -> if (roleActorBean.type == scriptConfig.groupRoleType){ usersInRole += scriptConfig.groupManager.getUsersInGroup(roleActorBean.typeParameter).key } else if (roleActorBean.type == scriptConfig.userRoleType){ usersInRole += roleActorBean.typeParameter } } } } return currentUser.key in usersInRole } /** * This function checks whether the user who edited the attribute is the owner of the object. https://documentation.mindville.com/display/INSSERV/Update+object+attribute * @param domainObject - An object that was updated * @param attributeName - A name of the attribute * @param currentUser - A user that * @return */ boolean isUserDomainOwner(def domainObject, String attributeName, ApplicationUser currentUser){ Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader(). findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade") def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass) def attributeBean = objectFacade.loadObjectAttributeBean(domainObject.getId(), attributeName) ArrayList<String> owners = [] if (attributeBean != null) { attributeValue = attributeBean.getObjectAttributeValueBeans() attributeValue.each{user -> owners += user.getValue().toLowerCase() } } if (owners.size() > 0){ log.warn("${object} is owned by ${owners}.") log.warn("Is ${currentUser.displayName} the Domain owner? ${owners.contains(currentUser.username.toLowerCase())}") return owners.contains(currentUser.key.toLowerCase()) } } /** * This function checks whether the user who edited the attribute is the Jira admin. * @param currentUser - user that triggered a change * @return TRUE/FALSE */ def isUserInJiraAdminGroup(ApplicationUser currentUser){ log.warn(currentUser) try{ log.warn(currentUser) return ComponentAccessor.getGroupManager().isUserInGroup(currentUser, scriptConfig.jiraAdminsGroup) } catch (Exception e){ log.warn(e.toString()) log.warn(e.stackTrace.toString()) } } /** * This function checks whether the user who edited the attribute is the svc account. * @param currentUser 0 user that triggered a change * @return */ boolean isUserSvcAccount (ApplicationUser currentUser){ return currentUser.username.toLowerCase() == scriptConfig.svcScriptRunner.username.toLowerCase() } /** * This function restores previous value in edited attribute. * @param insightObject - An object that was updated * @param oldValue - Old value of the object attribute * @param attributeId - An id of the attribute */ void updateAttributeInObject(def insightObject, ArrayList<String> oldValue, Integer attributeId){ // Set svc account ass current user ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(scriptConfig.svcScriptRunner) // Get Insight Object Facade from plugin accessor Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader() .findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade") def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass) def newObjectAttributeBean // Get Insight Object Attribute Facade from plugin accessor Class objectTypeAttributeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader() .findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade") def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeAttributeFacadeClass) // Get the factory that creates Insight Attributes Class objectAttributeBeanFactoryClass = ComponentAccessor.getPluginAccessor().getClassLoader() .findClass("com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory") def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(objectAttributeBeanFactoryClass) // This is the user object type attribute and the one we want to modify def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(attributeId) def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.getId(), objectTypeAttributeBean.getId()) // If old value is empty, script sets null in attribute value if(oldValue.size() > 0){ newObjectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, *oldValue) // Reuse the old id for the new attribute newObjectAttributeBean.setId(objectAttributeBean.getId()) // Store the object attribute into Insight. objectAttributeBean = objectFacade.storeObjectAttributeBean(newObjectAttributeBean) } else { // Clear attribute value objectAttributeBean = objectFacade.deleteObjectAttributeBean(objectAttributeBean.getId().longValue()) } } /** * This function adds comment if user is not allowed to edit attribute. * @param message - A message that is added as a comment * @param commentAuthor - An author of the comment * @param insightObject - An object where the comment is added * @param schemeRole - A role which can see the comment */ void addCommentToObject(String message, ApplicationUser commentAuthor, def insightObject, int schemeRole){ ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(scriptConfig.svcScriptRunner) Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader() .findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade") def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass) CommentBean commentBean = new CommentBean() commentBean.setComment(message) commentBean.setRole(schemeRole) commentBean.setAuthor(commentAuthor.getKey()) commentBean.setObjectId(insightObject.getId()) objectFacade.storeCommentBean(commentBean) }
- Edit any object
Expected Results
- A value of the attribute should be restored if the script was triggered by a user who is not allowed to edit it.
- The following comment should be added to the object
Dear <CURRENT_USER_DISPLAY_NAME> you are not allowed to edit Domain - Release First Approval Delegate attribute. Please contact with Domain Owner - First Approver or Jira Admins.
Actual Results
The script fails on line 71 without any errors logged to the log file.
Workaround
Change the name of groovy script to follow Java class name restriction, excluding '-' or any illegal characters for a Java class name.
This issue should not exist in JSM 10.x