In our last post we showed how we can validate candidate code prior to merging with a Pull Request. Pull Requests are a great way to validate code, but sometimes we need specific people to validate prior to merging.

Azure DevOps actually gives us a facility to automatically add approvers.  Automatic Approvers can be added based on file path patterns to help narrow the scope.

Automatic Approvers can be added in the “Automatically include code reviewers” section of our Policy Settings.  One can use Teams or individuals. For instance, we can automatically add an approver if a type of file changes.  

The Requirement field can be “Required” which means that a person (or a single person from a group) needs to approve no matter what (even if our threshold is met).  Additionally, the PR requester cannot remove the automatically required approver user/group if set to "required" (instead of "optional").

If the Requirement is optional, it automatically adds that person/group but they are not mandatory and moreover the PR requester can remove them if they feel they aren’t necessary.

A lot of times this can be a trust dilemma; do you trust your engineers to set the right people? Or do you have policies that really require a specific person or group to sign off on all PRs?

Each organization needs to determine that for themselves, however it’s my viewpoint that it should almost always be Optional and only use Required if it’s important to protect/review a specific type (e.g. database schema, or you want Judy 'the FDA expert' to review anytime the fda_codes.yaml changes).

For example, say we want Isaac the JSON wizard to approve any PRs that have json in them.

Note: i did this for an example, but I almost always set it to be a Team (group) with more than one person - that way people can be on PTO / Sick and work doesn’t get blocked. I’ll also assign a Manager or PM the ability to administer the group - this way they can be in charge of adding/removing people but not need Repo Administration rights.

Example:

Applying this setting to our existing policy, changes take effect immediately. The existing PR automatically changed and we see what was just marked “Reviewers” because “Required”:

The existing reviewer can satisfy the rule that requires 1 reviewer.  However, say the developer added their buddy as a reviewer, and they approved.  It would say 1 of 1 approved, but still would have a red x on the “Required reviewers” because their buddy wasn't in the set of required approvers.

Fork and PR model.

First we create a repo that blocks contributors from actually creating branches, tags or contribute:

One needs to explicitly deny Contribute and Create branch/tag

Now the standard user can view it, but that user cannot create a branch from the dropdown:

read only permission let's us view the branches, but not create

Instead, to actually contribute, I’ll need to create a forked repo, branch and a PR back:

First, create a fork:

If you really have the need, copy all the branches, but i generally just take the default (usually develop)

PRO-TIP: you will get an error about users not being able to create repositories unless you set that at the global permission level:

This fork creates it with my own namespace: idj-ta-example/_git/idj-lockeddown-example.isaac.johnson.

Now when i create a PR - can choose the source repository

Creating a PR from my fork
Selecting the original repo as the destination

The PR is created in the destination repository. That is, the PR object does not live the forked repo, rather the PR object is the destination with a reference to changes in the fork:

Looking at the PR in the original repository

Purpose:

This model, which has widely been popular with the open source community, makes the destination repository immutable to external changes - one cannot do anything in a repo and changes must be accepted by those with abilities on the destination.

The benefit, of course, is extra security at the cost of many more forks.  In this model, the active branches are always in other users repos and the only branches in the destination should be the live release branches (generally develop and master).

This can make hunting down active work a bit harder and users need to get comfortable syncing their fork up when changes occur.  However, the process is similar to syncing a branch and can be learned.  

This model is also very handy if you have an organization that tends to create a lot of WIP and you want to isolate that to users’ repos.

Summary

In this tutorial we have covered Azure DevOps and the many ways we have available to secure and validate our source through policies and pipelines.  We have explored most of what is available via settings and menus, however AzDO does have even more features hidden behind the REST API.  Additionally, while we have focused entirely on the GIT model, AzDO also supports TFVC (the logical successor to SourceSafe).