Granting a team permission to a GitHub repo using the API and PowerShell
When it comes to GitHub people generally think of Public repos and open source. But GitHub is a great tool for the enterprise also.
I have mentioned this before, take a look at Enterprise Managed Users (EMU). Asking GitHub to create an EMU enabled enterprise means direct connection to your Identity Provider, and no pesky personal GitHub id’s to deal with. To understand more about EMU read this.
Administering a GitHub Organization under EMU is different than a regular organization. As of this writing there are no public repos allowed, just private and internal. Under organization settings you can decide how you want to handle default access to the repos in your organization. If you have repos that you want to give explicit rights to then you will want Basic Permissions set to “No Permission”. Which means everyone in the org has read only permissions to internal repos and no access to private ones, without explicitly assigning a role hence the script below.
Under Base Permissions you can also select Read, Write and Admin. Which means they will have that permission on all repos in the Organization. Remember this is just an org level default setting.
When assigning explicit access to a repo there are 5 repository roles defined in GitHub Read, Triage, Write, Maintain and Admin. Check out this link to see what permissions each role has.
In my experience it works well to limit the base permissions to “no permissions”. If you have repos you want everyone to be able to read just make those repos internal. Everything else is Private and therefore requires explicit permissions.
Lets take a look at how we can grant those permissions using a script. For my example I’ll create a PowerShell script called addPermission.ps1 with:
- Three parameters: The name of the repo, the name of the team and the role we want to grant that team on that repo.
- A variable with the GitHub organization name. This could also be a parameter obviously.
- A variable with the Personal Access Token we will get from an environment variable, converted to base64.
param (
[Parameter(Mandatory=$true)] $repo,
[Parameter(Mandatory=$true)] $team,
[ValidateSet(“pull”,”push”,"triage",”maintain”,"admin")]
[Parameter(Mandatory=$true)] $role)
$org = "myOrg"
$pat = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($env:GH_PAT)"))
Notice the ValidateSet decorator on the role argument. This will ensure someone does not pass an incorrect role value. It’s easily done because it’s a bit confusing. The user interface and documentation both show these as options.
While the API has different names for Read and Write. When setting permissions using the API Read is passed in as pull and Write is push.
This is a very simple script the call to the API is:
orgs/<Org>/teams/<TeamSlug>/repos/<Owner>/<Repository>
The team slug is what you would see in the URL when you navigate to the team. Therefore it’s always lowercase. So we’ll add a line to ensue that.
The owner in our case is the same as the Org.
The Body requires just one parameter, permission. This is the role you want to assign to the team for this repo. For us it’s the argument role, passed in to script.
$teamSlug = $team.ToLower()
$body = @{permission=$role}
Now to pull all these parts together for the call to the API.
$params = @{
'Uri' =
('https://api.github.com/orgs/{0}/teams/{1}/repos/{0}/{2}' -f
$org, $teamSlug, $repo )
'Headers' = @{'Authorization' = 'Basic ' + $pat}
'Method' = 'PUT'
'ContentType' = 'application/json'
'Body' = ($body | ConvertTo-Json)}
Invoke-RestMethod @params
The call to our script will of course be something like this:
.\addPermission.ps1 -repo "MyRepo" -team "Developer" -role push
.\addPermission.ps1 -repo "MyRepo" -team "ProductOwner" -role triage
.\addPermission.ps1 -repo "MyRepo" -team "Architect" -role maintain
Also you can create custom roles that are based on an existing role, then add permissions to it. I’ll save that for another article.