We're using Visual Studio Team Services for our git server. Each Azure DevOps Project hosts one or many git repos. We have the convention of keeping master
and develop
branches locked-down, but letting other branches remain unrestricted.
I'd like to be able to apply our standard rules at the project-level and have them be the defaults for all repos within them:
master
and develop
should have their security deny Force Push
master
branch requires a Pull Request via a Code Review policySo far the only option I've found is to manually set these per-repository, through the web-interface (not even an API!). We have at least 200+ repositories and would love to avoid having to manually setup every repo and branch one by one.
How do I set default code security and code policies by branch name? Or by any way other than manually?
To set the policy, under Branch Policies, set Check for linked work items to On. This setting requires that work items be linked to a PR for the PR to merge. Make the setting Optional to warn when there are no linked work items, but allow completion of the pull request.
1. Get all git repositories for the team project.
GET https://account.visualstudio.com/DefaultCollection/ProjectName/_apis/git/repositories?api-version=1.0
Then save each git repo id and name from output.
2. Loop the repositories you got in step1 in your code by repo id, and create branch policy for each master branch (assume the minimum number of reviewers is 2 here).
POST https://account.visualstudio.com/DefaultCollection/ProjectName/_apis/policy/configurations?api-version=2.0-preview
Application/json:
{
"isEnabled": true,
"isBlocking": true,
"type": {
"id": "fa4e907d-c16b-4a4c-9dfa-4906e5d171dd"
},
"settings": {
"minimumApproverCount": 2,
"creatorVoteCounts": false,
"allowDownvotes": false,
"scope": [
{
"refName": "refs/heads/master",
"matchKind": "Exact",
"repositoryId": "{repo id}"
}
]
}
}
To script the Repository and branch security, you can use the tfssecurity.exe
or the new permissions REST API or the Azure CLI. All details in the following blog post:
For specific branches, add /refs^heads^master/
at the end of the Token.
If you've dug into the security innards of Azure DevOps in the past, you'll have found out that certain permissions are granted to persons or groups and are linked to a token. This token is usually built up out of a root object and a bunch of GUIDs. For example, this is the token for a specific Git Repository:
repoV2/daec401a-49b6-4758-adb5-3f65fd3264e3/f59f38e0-e8c4-45d5-8dee-0d20e7ada1b7
^ ^ ^
| | |
| | -- The Git Repository
| -- The Team Project Guid
|
-- The root object (Repositories)
Simplest way I know of to find these details, is to capture the web request made when a permission is changed:
You can use the Web Developer tools in your favorite browser to find the token you need. Once you understand this, it's easy to find the token for the "All Repositories in a Team Project" token. Just take off the Git Repository GUID at the end:
repoV2/daec401a-49b6-4758-adb5-3f65fd3264e3b7/
^ ^
| |
| -- The Team Project Guid
|
-- The root object (Repositories)
And, using the same reasoning, to get to the token for "All repositories in the Project Collection/Organization" token. Just take off the Team Project GUID at the end:
repoV2/
^
|
-- The root object (Repositories)
And now that we have this token, we can use tfssecurity to set Organization level git permissions:
tfssecurity /a+ "Git Repositories" repoV2/ "PullRequestBypassPolicy" adm: ALLOW /collection:https://dev.azure.com/org
^ ^ ^ ^ ^ ^
| | | | | -- Allow or Deny the permission
| | | | -- The Group (in this case "Project Collection Administrators")
| | | -- The Permission we want to set
| | -- The Token we found above
| -- The Secuity Namespace
-- Add (a+) or Remove (a-) this permission
And, as you can see below, this trick actually works :).
You can use the same technique to secure branches. The token of a branch uses the token of the Repository as a basis and adds the branch to that. Because a /
is a token separator, a branch reference is escaped by replacing /
with ^
. Thus refs/heads/master
becomes: refs^heads^master
:
repoV2/daec401a-49b6-4758-adb5-3f65fd3264e3/f59f38e0-e8c4-45d5-8dee-0d20e7ada1b7/refs^heads^master/
^ ^ ^ ^
| | | |
| | | -- The branch
| | -- The Git Repository
| -- The Team Project Guid
|
-- The root object (Repositories)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With