Best Practices Digest How-To's

Make It Workflow — Part 1: Restricting Issue Visibility

With this article, we begin a series of blog posts that demonstrate how to support specific processes in YouTrack with the help of workflows. This post is devoted to visibility restrictions. Specifically, we’ll show you how to restrict visibility so that each issue can be read by a very limited set of people and manage visibility independently for each issue in a project.

twitter_506x253@2x

Imagine that you have an accounting team whose members help other employees pay work-related invoices. The team processes payments for business trips, advertising, conferences, and the like. They use YouTrack as a means of transparent communication with other departments. Various employees create issues that contain the details of the requested payment and a copy of the invoice. The payment details and invoice are considered to be sensitive data. Therefore, each issue must visible only to the reporter and the members of the accounting team.

For this scenario, we have two different techniques to tackle the problem.

Workflow-free Mode

The most straightforward way to handle this scenario is to use the permission scheme in YouTrack.

First, define the groups of agents who participate in these issues:

  • Requesters. This is the collection of employees who are allowed to request payments from the accounting team. These people should be able to create requests, but should only be able to read the issues that they created themselves.
  • Executors. These are the members of the accounting team who process payment requests. Executors should be able to read and update any issue. Members of this team are expected to be in the list of Assignees.
  • Viewers. These are people who can read and update any issue, if necessary. This list includes, for example, the head of the accounting team or a company lawyer.

Note that the names that are assigned to these groups are different from the names that are assigned to the default roles in YouTrack. These names are used intentionally to avoid confusion.

To support this scenario, each of these groups (as a collection of users) is assigned a role that grants the appropriate level of access. They should have the following permissions:

  • Requesters – Members of this group require all of the permissions that are assigned to the default Reporter role except for Read Issue. Assign this group a custom role with the name Restricted Reporter and add permissions accordingly. For the list of permissions that are assigned to the default Reporter role, refer to the documentation.
  • Executors – Assign this group the default Developer role.
  • Viewers – Also assign this group the default Developer role.

You may wonder why there are two groups that are assigned the same role. It makes sense to separate executors and viewers so that you can add the Executors group to the set of values for the Assignee field. Any user who is added to this group is also added to the list of assignees. Users who are added to the Viewers group are not assignees.

Note that in the latest version of YouTrack the Executors group is redundant to the project team. Instead of creating a separate group, you can simply add executors to the project team directly.

The reason that you can satisfy the requirements for this scenario just by using permissions is that users who have the Create Issue permission in a project have permission to read and update the issues that they create themselves. Removing the Read Issue permission from the role that is assigned to the group of requesters prevents members of this group from reading issues that were created by other users.

The Workflow-enhanced Approach

The first scenario is very binary. Users can either read and update only the issues that they reported themselves, or access all of the issues in the project. In real life, the situation is usually much more complex. What happens when you want some people to read and update some issues — not just the issues they created, but also those which are shared with them somehow?

Consider what happens when you add the following requirement to the original scenario:

  • In addition to the user who created the issue, issues can be shared with another member of the Requester group.

First, let’s define what it means to “share an issue”. Here, you want to allow the user who submitted the payment request to add the name or login of another requester to the issue. This additional requester is then able to read and update the issue.

The permission scheme by itself does not support this. However, issues in YouTrack have two levels of read access:

  • The first level is permission-based.
  • The second level is based on issue visibility.

To read an issue, a user must have permission to read the issue in the project and belong to the list of users for whom the issue is visible.

YouTrack checks the permissions first. If they are sufficient, it then determines whether the user is a member of any group for which the issue is visible or has been added to the ‘visible to’ list as an individual.

By default, an issue is visible to the All Users group. The visibility is not restricted to specific users or groups. In this case, YouTrack only checks for permissions in the project.

To satisfy the additional requirement for this scenario, you can make minor adjustments to the permission scheme and rely on the visibility settings to restrict access.

First, change the role that is assigned to the Requesters group in the project from the custom role to the default Reporter role, which includes the Read Issue permission. Requesters now have permission to read any issue in the project unless the visibility is restricted to a group that excludes them.

Now you want to restrict the visibility of reported issues to executors and viewers. To simplify the setup, it’s best to pick one group or the other. If you restrict the visibility to both groups at the same time, you run the risk of having executors exclude viewers and vice versa. The workflows here restrict issue visibility to members of the Viewers group. To make issues visible to executors as well, add all of the executors to the Viewers group. The primary function of the Executors group is just to manage the list of possible users for the Assignee field.

You need to restrict visibility as soon as an issue is reported. Here’s a workflow rule that does just that.

var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');

exports.rule = entities.Issue.onChange({
  title: 'Set "Visible to" group on submit',
  guard: function(ctx) {
    return ctx.issue.becomesReported;
  },
  action: function(ctx) {
    ctx.issue.permittedGroups.add(ctx.viewers);
    workflow.message('Users from group "' + ctx.viewers.name +
                     '" can see this request.');
  },
  requirements: {
    viewers: {
      type: entities.UserGroup
    }
  }
});

Just as it was in the first scenario, each issue is still visible to its reporter and any member of the Viewers group. However, the reporter or any member of the Viewers group can “share” the issue with additional members of the Requesters group when necessary. To share the issue, the user can add a new person from the Requesters group to the “visible to” list. Profit!

Further Improvements

There are a number of other ways you can use workflows to manage visibility. You might consider adding one or more of the following rules to increase the flexibility of the entire scheme.

Automatically add users to the “visible to” list when they are @mentioned in a comment.

var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');

var loginRegex = /@(([A-Z0-9._@$+\-=|])*)/gi;

exports.rule = entities.Issue.onChange({
  title: 'Automatically add users to the "visible to" list',
  guard: function(ctx) {
    var issue = ctx.issue;
    return issue.comments.added.isNotEmpty() &&
      (issue.permittedGroups.isNotEmpty() || issue.permittedUsers.isNotEmpty());
  },
  action: function(ctx) {
    var issue = ctx.issue;
    var text = '';
    issue.comments.added.forEach(function (comment) {
      text += comment.text + '\n';
    });
    var message = '';
    var matches = text.match(loginRegex);
    if (matches) {
      matches.forEach(function(m) {
        var login = m.slice(1);
        if (login) {
          var user = entities.User.findByLogin(login);
          if (user) {
            issue.permittedUsers.add(user);
            message += 'User "' + user.fullName + 
                         '" is added to issue readers. ';
          } else {
            message += 'User with login "' + login + '" not found. ';
          }
        }
      });
    }
    if (message) {
      workflow.message(message);
    }
  },
  requirements: {}
});

Block changes to visibility group for reported issues.

// This rule assumes that issue visibility is set to a specific group
// at the moment when an issue becomes reported.
// Each project has its own visibility group.

var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');

exports.rule = entities.Issue.onChange({
  title: 'Block changes to visibility group for reported issues',
  guard: function(ctx) {
    var issue = ctx.issue;
    return issue.isReported && !issue.becomesReported &&
      issue.isChanged('permittedGroups');
  },
  action: function(ctx) {
    workflow.check(false,
      'You cannot change group visibility restrictions for reported issues. ' +
      'Instead, you can add single users to the "visible to" list.');
  },
  requirements: {}
});

Block users from removing other users from the “visible to” list.

var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');

exports.rule = entities.Issue.onChange({
  title: 'Do not remove users from "visible to" list',
  guard: function(ctx) {
    var issue = ctx.issue;
    return issue.permittedUsers.removed.isNotEmpty();
  },
  action: function(ctx) {
    workflow.check(false,
      'You cannot remove other users from the "visible to" list.');
  },
  requirements: {}
});

Automatically add users to the “visible to” list when they are selected in a custom field that stores a user type (for example, Authorizer or Verifier).

var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');

exports.rule = entities.Issue.onChange({
  title: 'Add Authorizer to the "visible to" list',
  guard: function(ctx) {
    var fs = ctx.issue.fields;
    return fs.isChanged(ctx.AuthBy) && fs.AuthBy;
  },
  action: function(ctx) {    
    var issue = ctx.issue;
    issue.permittedUsers.add(issue.fields.AuthBy);
    workflow.message('The issue is now visible to ' + 
                     issue.fields.AuthBy.fullName);
  },
  requirements: {
    AuthBy: {
      type: entities.User.fieldType,
      name: 'Authorizer'
    }
  }
});

You can modify this scheme as much as you want. For example, let’s assume that your company does not want executors to see payment requests that are processed by other executors. In this case, you can remove the executors from the Viewers group and use a modified version of the last workflow rule to add them to the “visible to” list automatically. Here, you could add users to the “visible to” list when they are set as the assignee.

We hope that you’ve found a rule or two that help you protect sensitive data from prying eyes. Stay tuned for our next post in this series where we’ll share workflows that you can use to restrict update access.

You also might want to watch our YouTrack Custom Workflow Repository in Git. We’ll be uploading all of the workflows that we introduce in this series to the repository and many, many more to come.

If you have any questions about the workflows in this article or other workflow-related riddles, join our YouTrack Workflow Community in Slack. Here, you can interact with our development team and see how other users support their business logic with workflows.

image description