Search code examples
azure-devopspermissionsazure-pipelinesazure-devops-rest-apiazure-repos

Azure Pipelines + Repos Rest API: Permissions for creating a Pull Request via API using System.AccessToken


I am trying to create a Pull Request from an Azure Pipeline, using the Repos REST API.

Instead of using a personal token, the pipeline is supposed to authenticate using the System.AccessToken Pre-defined variable. The Build Service role has all permissions on the repository.

Yet, I keep getting 403 returned.
Other requests thrown at the API work - so the token encoding appears to not be the issue. (#PrintStatementsAreAValidDebugger! ;) )

enter image description here

When I use my own PAT for the project - where I'm merely a contributor, I can create the PR no problem. So it is probably not the request itself.

With my team members, we have tried various things. The Build Service Agent has full permissions on the repository. The assumption is that when using the predefined pipeline variable System.AccessToken to authenticate, it's automatically using the Build Service Agent's identity.

When using my own token, the PR is created no problem.

enter image description here

Any idea what we might be missing?

edit: added the code.

# calling pipeline task

  - task: PowerShell@2
    displayName: create_pull_request
    inputs:
      #targetType: 'inline'
      filePath: 99_cicd/scripts/create_pr/create_pull_request.ps1
      arguments: '
        -source_branch "[SOURCE]" 
        -target_branch "[TARGET]" 
        -pr_title "TEST Merge " 
        -pr_description "Platzhalter"
        '
      workingDirectory: '$(Agent.BuildDirectory)/s/'
    env:
      repository_name: $(Build.Repository.Name)
      org_url: $(System.CollectionUri)
      project_name: $(System.TeamProject)
      SYSTEM_ACCESSTOKEN: $(System.AccessToken)

Called script

# called script
param(
    [string] $source_branch,
    [string] $target_branch,
    [string] $pr_title,
    [string] $pr_description
)

$org_url = $env:org_url
$project_name = $env:project_name
$repository_name = $env:repository_name

# encode Access Tokens for REST API Use
$bytes_PAT = [System.Text.Encoding]::ASCII.GetBytes(":$env:SYSTEM_ACCESSTOKEN")
$encoded_PAT = [System.Convert]::ToBase64String($bytes_PAT)

$encoded_source_branch = [System.Uri]::EscapeDataString($source_branch)
$encoded_target_branch = [System.Uri]::EscapeDataString($target_branch)

$base_url = "$org_url/$project_name/_apis/git/repositories/$repository_name"

# Create the JSON Body for the Pull Request
$jsonBody = @{
    "sourceRefName" = "refs/heads/$source_branch";
    "targetRefName" = "refs/heads/$target_branch";
    "title" = $pr_title;
    "description" = $pr_description;
    "isDraft" = $true
} | ConvertTo-Json

# Define the API URL to create the Pull Request
$api_url = "$base_url/pullrequests?api-version=7.0"

try{
    # Make the REST API call to create the Pull Request
    write-Host "Creating PR"
    $response = $response = Invoke-RestMethod -Uri $api_url -ErrorAction Stop -Body $jsonBody -Method Post -Headers @{
        "Authorization" = "Basic $encoded_PAT";
        "Content-Type" = "application/json"
    }
} catch {
    # Dig into the exception to get the Response details.
    # Note that value__ is not a typo.
    Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
    Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    Write-Host "There was an Error with the API Call..."

}


Solution

  • You need to grant the Contribute and Contribute to Pull Requests permissions to:

    1. Project Collection Build Service Accounts
    2. Project Build Service (username)
    3. Project Collection Build Service (username)

    enter image description here

    In addition, you can use the Create Pull Request extension that create the PR for you.