diff --git a/src/plus/integrations/providers/azure/azure.ts b/src/plus/integrations/providers/azure/azure.ts index aa9d41255894f..29b8ae0b787c6 100644 --- a/src/plus/integrations/providers/azure/azure.ts +++ b/src/plus/integrations/providers/azure/azure.ts @@ -24,6 +24,7 @@ import { Logger } from '../../../../system/logger'; import type { LogScope } from '../../../../system/logger.scope'; import { getLogScope } from '../../../../system/logger.scope'; import { maybeStopWatch } from '../../../../system/stopwatch'; +import { base64 } from '../../../../system/string'; import type { AzureProjectDescriptor, AzurePullRequest, @@ -334,7 +335,10 @@ export class AzureDevOpsApi implements Disposable { rsp = await wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () => fetch(url, { - headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, + headers: { + Authorization: `Basic ${base64(`PAT:${token}`)}`, + 'Content-Type': 'application/json', + }, agent: agent, signal: aborter?.signal, ...options, diff --git a/src/plus/integrations/providers/azureDevOps.ts b/src/plus/integrations/providers/azureDevOps.ts index aca87bc1d33c4..2d14dc867b626 100644 --- a/src/plus/integrations/providers/azureDevOps.ts +++ b/src/plus/integrations/providers/azureDevOps.ts @@ -8,6 +8,7 @@ import type { IssueOrPullRequest } from '../../../git/models/issueOrPullRequest' import type { PullRequest, PullRequestMergeMethod, PullRequestState } from '../../../git/models/pullRequest'; import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata'; import { getSettledValue } from '../../../system/promise'; +import { base64 } from '../../../system/string'; import type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider'; import { HostingIntegration } from '../integration'; import type { @@ -81,7 +82,10 @@ export class AzureDevOpsIntegration extends HostingIntegration< const account = await this.getProviderCurrentAccount(session); if (account?.id == null) return undefined; - const resources = await api.getAzureResourcesForUser(account.id, { accessToken: accessToken }); + const resources = await api.getAzureResourcesForUser(account.id, { + accessToken: convertTokentoPAT(accessToken), + isPAT: true, + }); this._organizations.set( accessToken, resources != null ? resources.map(r => ({ ...r, key: r.id })) : undefined, @@ -117,7 +121,10 @@ export class AzureDevOpsIntegration extends HostingIntegration< const azureProjects = ( await Promise.allSettled( resourcesWithoutProjects.map(resource => - api.getAzureProjectsForResource(resource.name, { accessToken: accessToken }), + api.getAzureProjectsForResource(resource.name, { + accessToken: convertTokentoPAT(accessToken), + isPAT: true, + }), ), ) ) @@ -164,7 +171,8 @@ export class AzureDevOpsIntegration extends HostingIntegration< projects.map(async project => { const repos = ( await api.getReposForAzureProject(project.resourceName, project.name, { - accessToken: accessToken, + accessToken: convertTokentoPAT(accessToken), + isPAT: true, }) )?.values; if (repos != null && repos.length > 0) { @@ -202,7 +210,8 @@ export class AzureDevOpsIntegration extends HostingIntegration< try { const merged = await api.mergePullRequest(this.id, pr, { ...options, - accessToken: accessToken, + accessToken: convertTokentoPAT(accessToken), + isPAT: true, }); return merged; } catch (ex) { @@ -306,8 +315,11 @@ export class AzureDevOpsIntegration extends HostingIntegration< project: string; }): Promise { const api = await this.getProvidersApi(); + if (this._session == null) return undefined; + return api.getRepo(this.id, repo.owner, repo.name, repo.project, { - accessToken: this._session?.accessToken, + accessToken: convertTokentoPAT(this._session.accessToken), + isPAT: true, }); } @@ -347,13 +359,15 @@ export class AzureDevOpsIntegration extends HostingIntegration< const projectInputs = projects.map(p => ({ namespace: p.resourceName, project: p.name })); const assignedPrs = ( await api.getPullRequestsForAzureProjects(projectInputs, { - accessToken: session.accessToken, + accessToken: convertTokentoPAT(session.accessToken), + isPAT: true, assigneeLogins: [user.username], }) )?.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects)); const authoredPrs = ( await api.getPullRequestsForAzureProjects(projectInputs, { - accessToken: session.accessToken, + accessToken: convertTokentoPAT(session.accessToken), + isPAT: true, authorLogin: user.username, }) )?.map(pr => this.fromAzureProviderPullRequest(pr, repoDescriptors, projects)); @@ -392,7 +406,8 @@ export class AzureDevOpsIntegration extends HostingIntegration< projects.map(async p => { const issuesResponse = ( await api.getIssuesForAzureProject(p.resourceName, p.name, { - accessToken: session.accessToken, + accessToken: convertTokentoPAT(session.accessToken), + isPAT: true, assigneeLogins: [user.username!], }) ).values; @@ -547,3 +562,7 @@ const azureCloudDomainRegex = /^dev\.azure\.com$|\bvisualstudio\.com$/i; export function isAzureCloudDomain(domain: string | undefined): boolean { return domain != null && azureCloudDomainRegex.test(domain); } + +function convertTokentoPAT(accessToken: string): string { + return base64(`PAT:${accessToken}`); +} diff --git a/src/plus/integrations/providers/providersApi.ts b/src/plus/integrations/providers/providersApi.ts index 4272406b53013..8cc6b59170ca4 100644 --- a/src/plus/integrations/providers/providersApi.ts +++ b/src/plus/integrations/providers/providersApi.ts @@ -611,7 +611,7 @@ export class ProvidersApi { async getAzureResourcesForUser( userId: string, - options?: { accessToken?: string }, + options?: { accessToken?: string; isPAT?: boolean }, ): Promise { const { provider, token } = await this.ensureProviderTokenAndFunction( HostingIntegrationId.AzureDevOps, @@ -620,7 +620,9 @@ export class ProvidersApi { ); try { - return (await provider.getAzureResourcesForUserFn?.({ userId: userId }, { token: token }))?.data; + return ( + await provider.getAzureResourcesForUserFn?.({ userId: userId }, { token: token, isPAT: options?.isPAT }) + )?.data; } catch (e) { return this.handleProviderError( HostingIntegrationId.AzureDevOps, @@ -732,7 +734,7 @@ export class ProvidersApi { provider.getAzureProjectsForResourceFn, azureToken, options?.cursor, - true, + options?.isPAT, ); } catch (e) { return this.handleProviderError>( @@ -746,7 +748,7 @@ export class ProvidersApi { async getReposForAzureProject( namespace: string, project: string, - options?: GetReposOptions & { accessToken?: string }, + options?: GetReposOptions & { accessToken?: string; isPAT?: boolean }, ): Promise> { const { provider, token } = await this.ensureProviderTokenAndFunction( HostingIntegrationId.AzureDevOps, @@ -760,6 +762,7 @@ export class ProvidersApi { provider.getReposForAzureProjectFn, token, options?.cursor, + options?.isPAT, ); } @@ -864,7 +867,7 @@ export class ProvidersApi { return ( await provider.getPullRequestsForAzureProjectsFn?.( { projects: projects, ...options }, - { token: azureToken, isPAT: true }, + { token: azureToken, isPAT: options?.isPAT }, ) )?.data; } catch (e) { @@ -971,7 +974,7 @@ export class ProvidersApi { async getIssuesForAzureProject( namespace: string, project: string, - options?: GetIssuesOptions & { accessToken?: string }, + options?: GetIssuesOptions & { accessToken?: string; isPAT?: boolean }, ): Promise> { const { provider, token } = await this.ensureProviderTokenAndFunction( HostingIntegrationId.AzureDevOps, @@ -985,6 +988,7 @@ export class ProvidersApi { provider.getIssuesForAzureProjectFn, token, options?.cursor, + options?.isPAT, ); }