Configure GitLab and Bitbucket integrations
Set WEB_ORIGIN to the public HTTPS dashboard origin. BattleTest derives its OAuth callbacks and repository webhook destinations from this value. Local HTTP is allowed only for localhost and 127.0.0.1.
Configure a stable GITHUB_TOKEN_ENCRYPTION_KEY containing 64 hexadecimal characters. The same key encrypts GitLab and Bitbucket access tokens, rotating refresh tokens and per-connection webhook secrets. Keep it with your backups. Do not change it on an existing deployment without migrating stored credentials.
GitLab application
Section titled “GitLab application”Create a server-side confidential application using GitLab’s OAuth application instructions. Select api, openid, profile and email scopes and register this redirect URI, replacing the origin with your own:
https://battletest.dev/api/scm/oauth/gitlab/callbackSet these variables on the API service through its secret configuration:
GITLAB_URL=https://gitlab.comGITLAB_OAUTH_CLIENT_ID=GITLAB_OAUTH_CLIENT_SECRET=GITLAB_URL can point to your self-managed GitLab HTTPS origin. It must have no path, query or credentials. The application must exist on that same instance. Changing the host requires reconnecting existing accounts.
BattleTest uses the authorization code flow with PKCE. The connecting GitLab account needs Maintainer or Owner access to provision project service accounts and install webhooks. GitLab 18.11 or later supports project service accounts without feature flags, including Free tiers subject to service-account limits.
When a maintainer enables a project, BattleTest creates a BattleTest bot service account scoped to that project, assigns Developer access and stores a separate encrypted API token. Review notes and statuses use this bot. Token rotation uses the bot’s own token; setup grants never publish reviews. You do not need a global GitLab bot account or bot token in server configuration.
Bitbucket Cloud consumer
Section titled “Bitbucket Cloud consumer”Create an OAuth consumer in the intended Bitbucket workspace’s settings. Make it a private consumer and register this callback, replacing the origin with your own:
https://battletest.dev/api/scm/oauth/bitbucket/callbackEnable these OAuth consumer permissions:
| Consumer permission | OAuth scope | Used for |
|---|---|---|
| Account: Read | account |
Identify the setup account and list its workspaces |
email |
Read verified email addresses for BattleTest sign-in | |
| Repositories: Read | repository |
Discover and verify repository metadata |
| Pull requests: Read | pullrequest |
Access change metadata during setup |
| Webhooks: Read and write | webhook |
Install and remove repository webhooks |
The consumer also supplies the identity and verified email for BattleTest sign-in. Bitbucket grants the permissions configured on its consumer for each authorization. These are setup permissions. BattleTest does not publish reviews using the authorizing account, even though the OAuth scope can permit commenting.
Set the consumer’s key and secret on the API service:
BITBUCKET_OAUTH_CLIENT_ID=BITBUCKET_OAUTH_CLIENT_SECRET=The integration uses Bitbucket Cloud’s API. Bitbucket Data Center is not supported by this adapter.
In a Bitbucket authorization URL, client_id is the consumer key. This URL authorizes an account; the Forge installation link below installs the BattleTest app. Start account connections from Settings → Integrations so BattleTest generates and validates the authorization state. A bare authorization link cannot complete a BattleTest connection.
Bitbucket Forge app
Section titled “Bitbucket Forge app”The scaffold is in the public battletest/battletest repository. Register it as BattleTest in your Atlassian developer space. The supplied manifest sends lifecycle events, pull request events and a five-minute scheduled authorization refresh to your API using app system tokens, with user tokens disabled.
- Use the Forge CLI to register the app and replace the placeholder
app.idin its manifest. - Set the manifest’s remote
baseUrlto your public dashboard origin. - Deploy to production, then enable sharing in the Atlassian developer console and copy the installation link.
- Set these API variables to the exact app and environment IDs from Forge and the installation link:
From the root of your battletest/battletest checkout, use Node.js 22 or 24 and run:
cd integrations/bitbucket-forgebunx @forge/cli loginbun run registerbun run lintbun run deploybunx @forge/cli environments list --jsonbunx @forge/cli install --environment production --product BitbucketFor the first installation, enter the shared workspace URL and approve the listed scopes. Use bunx @forge/cli install --upgrade --environment production --product Bitbucket after a deployment changes scopes or remote URLs on an existing installation. Check installations with bunx @forge/cli install list --json.
Forge login uses an Atlassian API token. Keep it in the local keychain or the CLI’s environment configuration. It is separate from the Bitbucket OAuth consumer secret. See Forge login.
BITBUCKET_FORGE_APP_ID=ari:cloud:ecosystem::app/<app-id>BITBUCKET_FORGE_ENVIRONMENT_ID=ari:cloud:ecosystem::environment/<app-id>/<environment-id>BITBUCKET_FORGE_INSTALL_URL=https://developer.atlassian.com/console/install/<installation-link>Use the app UUID from manifest.yml and the production environment UUID returned by environments list. Keep the full ari:cloud:ecosystem::environment/ value, including both UUIDs. The installation URL comes from Distribution → Sharing in the developer console; the distribution settings page and Bitbucket OAuth authorization URL are different links.
The API verifies Atlassian’s JWT signature, audience, issuer, expiry, environment, endpoint module and workspace before storing a system token. Tokens remain opaque, encrypted at rest and usable locally for at most ten minutes from the invocation; scheduled refresh maintains authorization. Reviews still re-check enabled repository selection on every operation. Failed provider authentication is an error, not a reason to use the setup user’s grant.
The Forge app requests read:app-system-token, read:user:bitbucket, read:repository:bitbucket, read:pullrequest:bitbucket and write:pullrequest:bitbucket. That write scope permits comments and broader PR actions. BattleTest uses comments and statuses, without approving or merging changes. The app does not request repository code-write scope.
Maintainers install this app in a shared Bitbucket workspace through Settings’ installation link before enabling repositories. Personal workspaces do not support Forge apps. See Forge Remote.
Sign-in and linked accounts
Section titled “Sign-in and linked accounts”Set AUTH_MODE=both to offer password sign-in and all configured social providers, or AUTH_MODE=oauth for social sign-in alone. local keeps password sign-in alone; github keeps GitHub sign-in alone. GitLab and Bitbucket reuse the applications and callback URLs above. Sign-in appears when that provider’s client ID and secret are configured. Bitbucket sign-in does not require a Forge installation.
Users can continue with a provider on the login or signup page, or link one in Settings → Account → Linked accounts. OPEN_SIGNUP=false blocks creation of new GitLab and Bitbucket accounts while allowing returning users to sign in. When a verified email already belongs to another BattleTest account, the user must sign in to that account and link the provider explicitly.
Linked accounts provide sign-in access. Repository connections in Settings → Integrations separately authorize reviews for an organisation. Users must keep at least one enabled sign-in method when unlinking accounts.
Routing and first connection
Section titled “Routing and first connection”Restart or redeploy the API after changing configuration. The web service must proxy these public endpoints to the API:
/api/scm/oauth/gitlab/callback/api/scm/oauth/bitbucket/callback/webhook/source-control/<connection-id>/webhook/forge/bitbucket
The shipped SvelteKit routes handle these paths. Keep them reachable through your reverse proxy. Repository connection callbacks require the same signed-in BattleTest user who started authorization. Sign-in callbacks validate browser state and create a BattleTest session; linking requires the account session that started the flow. Webhook delivery does not require a browser session.
Open Settings → Integrations, connect an account and select repositories. Do not manually copy a connection webhook URL to another project’s webhook configuration.
Reviews always use BattleTest automation identities. Instance administrators register the integrations once; repository maintainers authorize, install where required and select repositories without creating bot accounts.
Verify the deployment
Section titled “Verify the deployment”Use a disposable test repository with no sensitive code. Confirm OAuth returns to the intended workspace, enabling a repository installs one webhook, and a non-draft merge request or pull request targeting the default branch produces a review and status for the correct commit. Then push a new commit, change draft state, close the change and disconnect.
Also confirm a disabled repository and an invalid webhook signature cannot start reviews. Verify the displayed author is BattleTest bot, revoke its credential or uninstall the app, and confirm no review is posted as the maintainer. Test GitLab bot rotation and Bitbucket scheduled refresh, including a manual review after an idle period, before relying on unattended operation.