From 4b21b25c24035d6dc35459fef20a8bbb93661748 Mon Sep 17 00:00:00 2001 From: Joseph Roberto Date: Fri, 16 Jan 2026 09:11:29 -0600 Subject: [PATCH] fix: Bitbucket Cloud api token auth on git actions Signed-off-by: Joseph Roberto --- .../src/actions/bitbucketCloud.ts | 40 ++--------- .../src/actions/bitbucketCloudPullRequest.ts | 42 ++--------- .../src/actions/helpers.ts | 72 +++++++++++++++++-- 3 files changed, 78 insertions(+), 76 deletions(-) diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts index a278410639..d34235f633 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts @@ -24,8 +24,7 @@ import { } from '@backstage/plugin-scaffolder-node'; import { Config } from '@backstage/config'; -import { getAuthorizationHeader } from './helpers'; -import { getBitbucketCloudOAuthToken } from '@backstage/integration'; +import { getAuthorizationHeader, getGitAuth } from './helpers'; import { examples } from './bitbucketCloud.examples'; const createRepository = async (opts: { @@ -243,40 +242,9 @@ export function createPublishBitbucketCloudAction(options: { email: config.getOptionalString('scaffolder.defaultAuthor.email'), }; - let auth; - - if (ctx.input.token) { - auth = { - username: 'x-token-auth', - password: ctx.input.token, - }; - } else if ( - integrationConfig.config.clientId && - integrationConfig.config.clientSecret - ) { - const token = await getBitbucketCloudOAuthToken( - integrationConfig.config.clientId, - integrationConfig.config.clientSecret, - ); - auth = { - username: 'x-token-auth', - password: token, - }; - } else { - if ( - !integrationConfig.config.username || - !integrationConfig.config.appPassword - ) { - throw new Error( - 'Credentials for Bitbucket Cloud integration required for this action.', - ); - } - - auth = { - username: integrationConfig.config.username, - password: integrationConfig.config.appPassword, - }; - } + const auth = await getGitAuth( + ctx.input.token ? { token: ctx.input.token } : integrationConfig.config, + ); const signingKey = integrationConfig.config.commitSigningKey ?? diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts index 40dd09d386..01b556e6c2 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts @@ -27,8 +27,7 @@ import { } from '@backstage/plugin-scaffolder-node'; import { Config } from '@backstage/config'; import fs from 'fs-extra'; -import { getAuthorizationHeader } from './helpers'; -import { getBitbucketCloudOAuthToken } from '@backstage/integration'; +import { getAuthorizationHeader, getGitAuth } from './helpers'; import { examples } from './bitbucketCloudPullRequest.examples'; const createPullRequest = async (opts: { @@ -359,40 +358,11 @@ export function createPublishBitbucketCloudPullRequestAction(options: { const remoteUrl = `https://${host}/${workspace}/${repo}.git`; - let auth; - - if (ctx.input.token) { - auth = { - username: 'x-token-auth', - password: ctx.input.token, - }; - } else if ( - integrationConfig.config.clientId && - integrationConfig.config.clientSecret - ) { - const token = await getBitbucketCloudOAuthToken( - integrationConfig.config.clientId, - integrationConfig.config.clientSecret, - ); - auth = { - username: 'x-token-auth', - password: token, - }; - } else { - if ( - !integrationConfig.config.username || - !integrationConfig.config.appPassword - ) { - throw new Error( - 'Credentials for Bitbucket Cloud integration required for this action.', - ); - } - - auth = { - username: integrationConfig.config.username, - password: integrationConfig.config.appPassword, - }; - } + const auth = await getGitAuth( + ctx.input.token + ? { token: ctx.input.token } + : integrationConfig.config, + ); const gitAuthorInfo = { name: diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts index 47a212fcab..a2954570d8 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts @@ -37,15 +37,28 @@ export const getBitbucketClient = async (config: { }); } - if (config.token) { + // Standalone token (Bearer) + if (config.token && !config.username) { return new Bitbucket({ auth: { token: config.token, }, }); - } else if (config.username && config.appPassword) { - // TODO: appPassword can be removed once fully - // deprecated by BitBucket on 9th June 2026. + } + + // Username + API token (new method) + if (config.username && config.token) { + return new Bitbucket({ + auth: { + username: config.username, + password: config.token, + }, + }); + } + + // TODO: appPassword can be removed once fully + // deprecated by BitBucket on 9th June 2026. + if (config.username && config.appPassword) { return new Bitbucket({ auth: { username: config.username, @@ -53,6 +66,7 @@ export const getBitbucketClient = async (config: { }, }); } + throw new Error( `Authorization has not been provided for Bitbucket Cloud. Please provide either OAuth credentials (clientId/clientSecret), username and token, or username and appPassword in the Integrations config`, ); @@ -92,3 +106,53 @@ export const getAuthorizationHeader = async (config: { `Authorization has not been provided for Bitbucket Cloud. Please provide either OAuth credentials (clientId/clientSecret), username and token, or username and appPassword in the Integrations config`, ); }; + +export const getGitAuth = async (config: { + username?: string; + appPassword?: string; + token?: string; + clientId?: string; + clientSecret?: string; +}): Promise<{ username: string; password: string }> => { + // OAuth authentication + if (config.clientId && config.clientSecret) { + const token = await getBitbucketCloudOAuthToken( + config.clientId, + config.clientSecret, + ); + return { + username: 'x-token-auth', + password: token, + }; + } + + // Standalone token (Bearer) + if (config.token && !config.username) { + return { + username: 'x-token-auth', + password: config.token, + }; + } + + // Username + API token (new method) + // For git operations, use the static username 'x-bitbucket-api-token-auth' + if (config.username && config.token) { + return { + username: 'x-bitbucket-api-token-auth', + password: config.token, + }; + } + + // TODO: appPassword can be removed once fully + // deprecated by BitBucket on 9th June 2026. + if (config.username && config.appPassword) { + return { + username: config.username, + password: config.appPassword, + }; + } + + throw new Error( + `Authorization has not been provided for Bitbucket Cloud. Please provide either OAuth credentials (clientId/clientSecret), username and token, or username and appPassword in the Integrations config`, + ); +};