Azure DevOps Integration
Last updated: August 1, 2026
Goal: Make an Azure DevOps service account that is only for Aisle. Make a Personal Access Token (PAT) for this account. Then enter the PAT into Aisle.
This guide covers Azure DevOps Services (cloud) and Azure DevOps Server (self-hosted). One Aisle connection covers one organization (Services) or one collection (Server). To analyze repositories from more organizations or collections, do the steps again for each one.
For the Microsoft documentation, see Use personal access tokens.
Do the procedure in “Steps”. The sections after the steps give reference data: permissions, webhook subscriptions, and problem solutions.
Prerequisites
You must have access to an Aisle subscription. Your RBAC role must be
AdminorCISO. These roles are necessary to add repositories in Aisle.You must have a list of the repositories that Aisle will analyze.
Aisle needs a dedicated account (the service account). The account comes from your directory:
Services: a Microsoft Entra ID user in your organization.
Server: an Active Directory account, or a local Windows account on the Azure DevOps Server machine.
The service account must have the Basic access level. This level grants access to Azure Repos (see access levels).
Applicable versions: Azure DevOps Services, and Azure DevOps Server 2020, 2022, or newer. These server versions have the REST API version 6.0 or newer, which Aisle needs.
Server only: do the checks in “Azure DevOps Server” before the steps.
Necessary operator roles
You, the operator, need special permissions to prepare the service account for Aisle. These tasks are one-time.
Project Collection Administrator: to add the service account, to set its access level, and to grant the Service Hooks permissions. You cannot assign the Service Hooks permissions in the Azure DevOps web portal (see subscription permissions).
Project Administrator: a Project Administrator of each project can add the service account to the Contributors group (step 2). The other one-time tasks need the Project Collection Administrator role.
Directory administrator: Azure DevOps does not make these accounts. For Services, a Microsoft Entra ID administrator makes the user in your tenant. For Server, the account must exist in Active Directory, or as a local Windows account on the Azure DevOps Server machine, before you can add it to the collection.
Azure DevOps Server
Before onboarding of an Azure DevOps Server instance, make sure that these conditions are true:
The server version is Azure DevOps Server 2020, 2022, or newer.
Your server is available from the internet and has a public DNS record.
If necessary, Aisle can give you its static IP addresses. You can then limit the inbound access to Aisle only.
Your server can send outbound HTTPS traffic to Aisle at
https://{customer}.app.aisle.cloud.Your server uses HTTPS with a certificate from a public CA. Do not use self-signed certificates or certificates from internal CAs.
The Public URL in the Azure DevOps Server Administration Console is the same as the collection URL that you register in Aisle. The webhook payloads carry this URL, and Aisle uses it to identify your server. When the two URLs are different, Aisle ignores the events (see public URL settings). The URL must contain a public DNS name, not an internal name. Aisle rejects URLs with internal or private hostnames.
If you have a security proxy, make sure that the proxy does not change the requests or the responses. The proxy must not intercept the outbound TLS traffic to Aisle and sign it again with an internal CA.
Steps
Ask your directory administrator to create the service account. For Services, this is a Microsoft Entra ID administrator. For Server, this is an Active Directory or Windows administrator. Give it a name such as
aisle,aisle-bot, oraisle-service. A clear name identifies the actions of Aisle in an audit. Commits, pull requests, and comments then show as, for example, “aisle-bot”, and not as a personal user account.Add the account to your organization (Services) or collection (Server). Set the Basic access level.
Add the service account to the Contributors group of each project that Aisle will analyze.
Do not remove the Contributors membership. It gives permission to read the repositories, to push branches, to make pull requests, and to post comments and statuses.
Add the service account only to the projects that you will onboard to Aisle.
Grant the Service Hooks permissions View subscriptions and Edit subscriptions to the service account in each project. For the procedure, see “Account permissions”. If your security policy does not permit these permissions, skip this step and see “Manual webhook setup”.
Log in as the service account. Select your avatar. Then select Security → Personal access tokens → New Token. Make a new PAT with this data:
Token name:
Aisle IntegrationOrganization: the organization (Services) or collection (Server) that Aisle will connect to. Do not select “All accessible organizations”.
Expiration date: the end of the Aisle engagement, or later (the maximum is one year)
Scopes: select Custom defined. Click Show all scopes. Then select the six scopes from the table in “PAT scopes”.
Copy the token immediately. Azure DevOps shows the token only one time.
Enter the PAT into Aisle:
Note: You can connect Azure DevOps during the initial Aisle setup or after. The initial Aisle platform setup needs a connection to a minimum of one repository from an applicable VCS provider.
Go to
https://{customer}.app.aisle.cloud/app/integrations/vcs. As an alternative, click Integrations → VCS Connections in the left panel.Click the Add Azure DevOps button. Enter this data:
Integration Name: the name of this connection in Aisle, for example
ado-prodAzure DevOps Organization / Server URL: the full organization or collection URL (see the note below)
Access Token: the PAT from step 4
Click Add Azure DevOps. When the credentials are correct, the connection shows “Connected” and the date.
Note: Enter the full URL, with the organization or collection path:
Services:
https://dev.azure.com/{your-organization}. If your organization uses a legacy URL (https://{organization}.visualstudio.com), enter it in the formhttps://dev.azure.com/{organization}Server: the full collection URL, for example
https://devops.company.com/DefaultCollection. The hostname alone is not sufficient.
On the Azure DevOps connection, click Import Repositories. Then select the repositories that Aisle will analyze.
We recommend that you enter the context for the imported repositories before you turn on the Analyzer. Enter the context at
https://{customer}.app.aisle.cloud/app/custom-context. For more data, see Context in Aisle: how it works and how to use it.In the Repositories section of Aisle, click Enable Analyzer in the row of each repository.
Do a check of the branch policies and merge settings
Azure DevOps sets the restrictions for each project and each repository. Open each applicable repository. Then examine Project settings → Repositories → [repository] → Policies and the branch policies of the target branch.
Branch policies: Aisle makes branches with the name
aisle-fix-{issue-slug}-{fix-id}. The fix ID is the first 8 characters. Aisle opens pull requests into the branch that you set for the repository in Aisle. The initial value is the default branch. Policies for approvals, reviewers, and comment resolution apply to Aisle pull requests. This is usually the correct behavior — your team reviews each fix.Branch name limits: Make sure that no policy or path permission blocks the
aisle-fix-*branches.Build validation: A build-validation policy starts your pipelines on Aisle pull requests. This is permitted. With the Build — Read scope, Aisle reads the results of these pipeline runs (Azure DevOps Services only).
Status checks: If a policy needs the “Aisle PR Scanner” status, make sure that the PAT has the Code — Status scope. Without the scope, the status never arrives, and the policy blocks the merge.
Commit author: Aisle makes commits with the display name and the email of the service account. If the repository policy Commit author email validation is on (Project settings → Repositories → Policies), make sure that the patterns permit the email of the service account. If the service account has no email address, Aisle uses a fallback address that ends with
@noreply.invalid.
Reference
These sections give the details for the steps: permissions, scopes, and webhook subscriptions. You do not need to read them in order.
PAT scopes
Aisle needs these six scopes. The table shows the purpose of each scope and the effect when the scope is missing.
Note: Azure DevOps has no interface that shows the scopes of a PAT. During the connection, Aisle makes sure that the URL is correct, that the PAT authenticates, and that the account is found. Aisle cannot examine the scopes. A missing scope or permission shows as an error when Aisle first does the related operation.
Scope | Purpose | Without this scope |
|---|---|---|
Code — Read & write ( | Aisle lists repositories and branches, clones code, pushes fix branches, and makes and updates pull requests. | Nothing operates. This is the base scope. |
Code — Status ( | Aisle posts the “Aisle PR Scanner” status on commits and pull requests. | Findings come only as comments. A branch policy that needs the status blocks the merges. |
Build — Read ( | Aisle reads the results of the pipelines that run for a fix pull request. Aisle uses the results to validate the fix (CI validation). | CI validation is not available. Aisle cannot see if the builds of a fix pull request pass. |
Pull Request Threads — Read & write ( | Aisle posts and updates analysis findings as comments on pull requests. | The analysis operates, but Aisle cannot deliver the findings to the pull request. |
Project and Team — Read ( | Aisle finds the ID of each project. The webhook subscriptions need this ID. | Aisle cannot make the webhook subscriptions automatically (see “Manual webhook setup”). |
Notifications — Read, write, & manage ( | Aisle makes and controls its Service Hooks subscriptions. | Aisle cannot make the webhook subscriptions automatically (see “Manual webhook setup”). |
Note: The PAT interface has no separate scope for Service Hooks. The Notifications scope controls the Service Hooks API.
Account permissions
The PAT scopes and the account permissions are two independent controls. A scope opens an API category for the token. The account must also have the permission for the operation. A correct PAT with a missing account permission gets a 403 error.
Repository permissions
Aisle needs the permissions of the Contributors group. Step 2 adds the service account to this group. The Read permission lets Aisle list and clone the repositories. The Contribute permission lets Aisle push fix branches, make and abandon pull requests, and post statuses. The Contribute to pull requests permission lets Aisle write comments on pull requests.
Without Contribute, Aisle can read the repositories but cannot make pull requests or statuses.
If your security policy does not permit the Contributors group, you can grant the three permissions one by one, per repository. Go to Project settings → Repositories → [repository] → Security. The table shows the permission that each Aisle operation needs:
Operation | Necessary permission | Minimum group |
|---|---|---|
List repositories, branches, and pull requests | Read | Readers |
Make and abandon pull requests; post statuses | Contribute | Contributors |
Make and update comments on pull requests | Contribute to pull requests | Readers (this group has the permission by default) |
The account also needs View project-level information. All project members have this permission by default.
Service Hooks permissions
The permissions View subscriptions and Edit subscriptions control the webhook subscriptions. By default, only administrator groups have them. You cannot assign these permissions in the Azure DevOps web portal. A Project Collection Administrator must grant them to the service account with a command-line tool or with the REST API. Use these values:
Security namespace:
ServiceHooks, IDcb594ebe-87dd-4fc9-ac2c-6a10a4c92046Token:
PublisherSecurity/<projectId>— use the ID (GUID) of the project, not the project namePermission bits:
1(View subscriptions) +2(Edit subscriptions) =3
Azure DevOps Services only: use the Azure DevOps CLI. This example operates only with dev.azure.com:
# Get the project ID (copy the "id" value)
az devops project show --project "<project-name>" \
--org https://dev.azure.com/<organization> --query id -o tsv
# Grant View (1) + Edit (2) = 3
az devops security permission update \
--namespace-id cb594ebe-87dd-4fc9-ac2c-6a10a4c92046 \
--subject <service-account-email> \
--token "PublisherSecurity/<projectId>" \
--allow-bit 3 \
--org https://dev.azure.com/<organization>Azure DevOps Services, REST alternative: the Security REST API also operates on Services. Use the same three calls as the Server example below, with the base URL https://dev.azure.com/{organization}. One difference: get the identity descriptor from https://vssps.dev.azure.com/{organization}/_apis/identities?searchFilter=General&filterValue=<service-account-email>&api-version=6.0. For the payload structure, see Manage security namespaces and tokens.
Azure DevOps Server: Use the Security REST API against your collection URL. The example below operates on Server 2020 and newer (api-version=6.0). Use the PAT of a Project Collection Administrator for these calls, not the PAT of the service account. Make this administrator PAT with a short expiration date. Revoke it after this procedure.
# 0. Enter the administrator PAT (kept out of the shell history)
read -s ADO_PAT
# 1. Get the project ID (copy the "id" value)
curl -u ":$ADO_PAT" \
"https://devops.company.com/DefaultCollection/_apis/projects/<project-name>?api-version=6.0"
# 2. Get the identity descriptor of the service account (copy the "descriptor" value)
curl -u ":$ADO_PAT" \
"https://devops.company.com/DefaultCollection/_apis/identities?searchFilter=AccountName&filterValue=DOMAIN%5Caisle-bot&api-version=6.0"
# 3. Grant View (1) + Edit (2) = 3
curl -u ":$ADO_PAT" -X POST -H "Content-Type: application/json" \
"https://devops.company.com/DefaultCollection/_apis/accesscontrolentries/cb594ebe-87dd-4fc9-ac2c-6a10a4c92046?api-version=6.0" \
-d '{
"token": "PublisherSecurity/<project-id>",
"merge": true,
"accessControlEntries": [
{ "descriptor": "<descriptor>", "allow": 3, "deny": 0 }
]
}'The operations that Aisle does in Azure DevOps
Read: Aisle reads the repository contents, the branches, and the pull requests.
Monitor: Aisle makes webhook subscriptions on each project (see “Service Hooks subscriptions”).
Write: Aisle makes pull requests, comments on pull requests, and commit and pull request statuses.
Push: Aisle pushes only to its own
aisle-fix-*branches. Aisle does not push to your default branch or to protected branches. Each fix comes as a pull request.Merge: Aisle does not complete (merge) pull requests. Your team reviews and completes them. When a newer fix replaces an old fix pull request, Aisle abandons the old pull request and deletes its branch.
Service Hooks subscriptions
Aisle makes the webhook subscriptions at the project level. One set covers all repositories of a project. Azure DevOps does not permit one subscription for more than one event type. Thus Aisle makes one subscription for each event type. The subscriptions authenticate with Basic authentication, and Azure DevOps encrypts the secret at rest. Aisle controls and repairs its subscriptions automatically.
Event | Purpose |
|---|---|
| Keep the repository list in Aisle correct. A scheduled synchronization also corrects the repository list if an event is lost. |
| Start the incremental analysis after a merge. Aisle processes only the pushes to the branch that is set for the repository. Aisle ignores tag pushes and branch deletions. |
| Start the analysis of a new pull request. Draft pull requests do not start an analysis. |
| Start the analysis again after new commits, or when a draft becomes ready, or when a pull request is abandoned. |
| Set the related issue to “resolved” when a fix pull request merges. |
| Permit a manual analysis. Write a comment that contains |
| Send the pipeline job results to Aisle. Aisle uses them for the CI validation of fix pull requests. This event is available on Azure DevOps Services only. |
Manual webhook setup (alternative)
If your security policy does not permit the Service Hooks permissions or the Notifications scope, your team can make the subscriptions manually. This procedure replaces step 3. Do it after step 5, when the connection exists in Aisle, and before you import the repositories (step 6):
Ask Aisle for the external webhook credentials. You get the webhook URL, a username, a password, and the list of the event types.
In each applicable project, go to Project settings → Service hooks. Make one Web Hooks subscription for each event type. Enter the Aisle webhook URL and the Basic authentication credentials.
In step 4, omit the Notifications and Project and Team scopes from the PAT.
Caution: With the manual setup, Aisle does not control or repair the subscriptions. Keep the subscriptions in place.
Replace the PAT
Azure DevOps sets a maximum lifetime of one year for tokens. Replace the PAT before the expiration date:
In Azure DevOps, log in as the service account. Make a new PAT with the same scopes as in step 4.
In Aisle, go to Integrations → VCS Connections.
On the Azure DevOps connection, open the menu. Then select Update Connection.
Enter the new PAT in the Access Token field. Then click Save.
In Azure DevOps, revoke the old token.
Note: If the token expires, the connection shows “Invalid Token”. Aisle operations stop until you enter a new token.
Troubleshooting
Problem | Action |
|---|---|
The connection shows “Invalid Token” | Make sure that the PAT is not expired and not revoked. An Azure DevOps connection shows “Invalid Token” also for an expired token. Make a new PAT. Then enter it with Update Connection. |
The connection is correct, but an operation fails with a 403 error | Make sure that the PAT has all scopes from “PAT scopes”. Make sure that the account has the permissions from “Account permissions”. Azure DevOps cannot show the scopes of a token. |
Some repositories do not show in the import list | Make sure that the service account is a member of the Contributors group for those projects. |
The import list is empty, or each import fails | Make sure that the server URL and the Public URL contain the public DNS name of the server, not an internal name. |
Aisle cannot make the webhook subscriptions (403 error) | Make sure that the service account has View subscriptions and Edit subscriptions (see “Account permissions”). The Notifications scope alone is not sufficient. |
Events do not arrive: no analysis after a push or a pull request | In Azure DevOps, go to Project settings → Service hooks. Make sure that the Aisle subscriptions are in the list and that the deliveries are successful. On Server, make sure that the Public URL is the same as the registered collection URL. |
The “Aisle PR Scanner” status does not show | Make sure that the PAT has the Code — Status scope. |
A fix pull request does not open | Make sure that the account has the Contribute permission. Do the checks in “Do a check of the branch policies and merge settings”. |
Off-boarding
When you disconnect Aisle, revoke the PAT:
In Aisle, remove the connected repositories or the full Azure DevOps integration first. Aisle then deletes its webhook subscriptions while the PAT is serviceable. If you revoke the PAT first, the subscriptions stay on the projects. You must then remove them manually in Project settings → Service hooks.
In Azure DevOps, log in as the service account. Select your avatar. Then select Security → Personal access tokens. Find the
Aisle Integrationtoken. Then select Revoke.
You can deactivate the service account as an alternative to deletion. A deactivated account keeps a clear identity in the audit history. On Server, deactivate the account in Active Directory.