diff --git a/CHANGELOG.md b/CHANGELOG.md index 22893b352c1..e3a46c3e18d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,30 @@ All notable changes to Sourcegraph are documented in this file. - The feature-flag `search-ranking`, which allowed to disable the improved ranking introduced in 5.1, is now deprecated and will not be read anymore. [#57468](https://github.com/sourcegraph/sourcegraph/pull/57468) - The GitHub Proxy service is no longer required and has been removed from deployment options. [#55290](https://github.com/sourcegraph/sourcegraph/issues/55290) -## Unreleased 5.2.2 +## Unreleased 5.2.4 + +### Added + +### Fixed + +- Fixed two issues in Zoekt that could cause out of memory errors during search indexing. [sourcegraph/zoekt#686](https://github.com/sourcegraph/zoekt/pull/686), [sourcegraph/zoekt#689](https://github.com/sourcegraph/zoekt/pull/689) + +### Changed + +### Removed + +## 5.2.3 + +### Added + +- Added configurable GraphQL query cost limitations to prevent unintended resource exhaustion. Default values are now provided and enforced, replacing the previously unlimited behaviour. For more information, please refer to: [GraphQL Cost Limits Documentation](https://docs.sourcegraph.com/api/graphql#cost-limits). See details at [#58346](https://github.com/sourcegraph/sourcegraph/pull/58346). +- Sourcegraph now supports connecting to Bitbucket Cloud using Workspace Access Tokens. [#58465](https://github.com/sourcegraph/sourcegraph/pull/58465). + +### Fixed + +- Defining file filters for embeddings jobs no longer causes all files to be skipped if `MaxFileSizeBytes` isn't defined. [#58262](https://github.com/sourcegraph/sourcegraph/pull/58262) + +## 5.2.2 ### Added diff --git a/cmd/frontend/backend/external_services_test.go b/cmd/frontend/backend/external_services_test.go index d52194987bd..cf07ce8c2a0 100644 --- a/cmd/frontend/backend/external_services_test.go +++ b/cmd/frontend/backend/external_services_test.go @@ -41,7 +41,7 @@ func TestAddRepoToExclude(t *testing.T) { kind: extsvc.KindBitbucketCloud, repo: makeBitbucketCloudRepo(), initialConfig: `{"appPassword":"","url":"https://bitbucket.org","username":""}`, - expectedConfig: `{"appPassword":"","exclude":[{"name":"sg/sourcegraph"}],"url":"https://bitbucket.org","username":""}`, + expectedConfig: `{"exclude":[{"name":"sg/sourcegraph"}],"url":"https://bitbucket.org"}`, }, { name: "second attempt of excluding same repo is ignored for BitbucketServer schema", diff --git a/doc/admin/external_service/bitbucket_cloud.md b/doc/admin/external_service/bitbucket_cloud.md index 2bede0d83e0..200a8c91754 100644 --- a/doc/admin/external_service/bitbucket_cloud.md +++ b/doc/admin/external_service/bitbucket_cloud.md @@ -18,6 +18,49 @@ In addition, there is one more field for configuring which repositories are mirr - [`teams`](bitbucket_cloud.md#configuration)
A list of teams (workspaces) that the configured user has access to whose repositories should be synced. - [`exclude`](bitbucket_cloud.md#configuration)
A list of repositories to exclude, which takes precedence over the `teams` field. +## Configuration options + +Bitbucket Cloud code host connections can be configured with either a username and app password combination, or with workspace access tokens. + +### Username and app password + +1. Visit your [Bitbucket account settings page](https://bitbucket.org/account/settings). +2. Navigate to **App passwords**. +3. Select **Create app password**. +4. Give your app password a label. +5. Select the `Projects: Read` permission. `Repositories: Read` should automatically be selected. +6. Press **Create**. + +Use the newly created app password and your username to configure the Bitbucket Cloud connection: + +```json +{ + "url": "https://bitbucket.org", + "username": "USERNAME", + "appPassword": "", + // ... other settings +} +``` + +### Workspace access token + +1. Visit the Bitbucket Cloud workspace settings page of the workspace you want to create an access token for. +2. Navigate to **Security > Access tokens**. +3. Press **Create workspace access token**. +4. Give your access token a name. +5. Select the `Projects: Read` permission. `Repositories: Read` should automatically be selected. +6. Press **Create**. + +Use the newly created access token to configure the Bitbucket Cloud connection: + +```json +{ + "url": "https://bitbucket.org", + "accessToken": "ACCESS_TOKEN", + // ... other settings +} +``` + ### HTTPS cloning Sourcegraph clones repositories from your Bitbucket Cloud via HTTP(S), using the [`username`](bitbucket_cloud.md#configuration) and [`appPassword`](bitbucket_cloud.md#configuration) required fields you provide in the configuration. diff --git a/internal/authz/providers/authz_test.go b/internal/authz/providers/authz_test.go index 58ec07ee37c..592fdd366be 100644 --- a/internal/authz/providers/authz_test.go +++ b/internal/authz/providers/authz_test.go @@ -1100,6 +1100,16 @@ func TestValidateExternalServiceConfig(t *testing.T) { }`, assert: equals(""), }, + { + kind: extsvc.KindBitbucketCloud, + desc: "valid with url, accessToken", + config: ` + { + "url": "https://bitbucket.org/", + "accessToken": "access-token" + }`, + assert: equals(""), + }, { kind: extsvc.KindBitbucketCloud, desc: "valid with url, username, appPassword, teams", @@ -1114,12 +1124,10 @@ func TestValidateExternalServiceConfig(t *testing.T) { }, { kind: extsvc.KindBitbucketCloud, - desc: "without url, username nor appPassword", + desc: "without url", config: `{}`, assert: includes( "url is required", - "username is required", - "appPassword is required", ), }, { diff --git a/internal/batches/sources/bitbucketcloud.go b/internal/batches/sources/bitbucketcloud.go index 55b218dca21..2e0dba91311 100644 --- a/internal/batches/sources/bitbucketcloud.go +++ b/internal/batches/sources/bitbucketcloud.go @@ -23,9 +23,7 @@ type BitbucketCloudSource struct { client bitbucketcloud.Client } -var ( - _ ForkableChangesetSource = BitbucketCloudSource{} -) +var _ ForkableChangesetSource = BitbucketCloudSource{} func NewBitbucketCloudSource(ctx context.Context, svc *types.ExternalService, cf *httpcli.Factory) (*BitbucketCloudSource, error) { rawConfig, err := svc.Config.Decrypt(ctx) diff --git a/internal/extsvc/bitbucketcloud/client.go b/internal/extsvc/bitbucketcloud/client.go index 1118f5a77e6..355553c8773 100644 --- a/internal/extsvc/bitbucketcloud/client.go +++ b/internal/extsvc/bitbucketcloud/client.go @@ -103,13 +103,20 @@ func newClient(urn string, config *schema.BitbucketCloudConnection, httpClient h return nil, err } + var auther auth.Authenticator + if config.AccessToken != "" { + auther = &auth.OAuthBearerToken{Token: config.AccessToken} + } else { + auther = &auth.BasicAuth{ + Username: config.Username, + Password: config.AppPassword, + } + } + return &client{ httpClient: httpClient, URL: extsvc.NormalizeBaseURL(apiURL), - Auth: &auth.BasicAuth{ - Username: config.Username, - Password: config.AppPassword, - }, + Auth: auther, // Default limits are defined in extsvc.GetLimitFromConfig rateLimit: ratelimit.NewInstrumentedLimiter(urn, ratelimit.NewGlobalRateLimiter(log.Scoped("BitbucketCloudClient", ""), urn)), }, nil diff --git a/internal/repos/bitbucketcloud.go b/internal/repos/bitbucketcloud.go index 0360e85a401..04c0857cb0a 100644 --- a/internal/repos/bitbucketcloud.go +++ b/internal/repos/bitbucketcloud.go @@ -238,7 +238,6 @@ func (s *BitbucketCloudSource) WithAuthenticator(a auth.Authenticator) (Source, sc.client = sc.client.WithAuthenticator(a) return &sc, nil - } // ValidateAuthenticator validates the currently set authenticator is usable. diff --git a/internal/repos/bitbucketcloud_test.go b/internal/repos/bitbucketcloud_test.go index f0630809bdc..b5a7ac62464 100644 --- a/internal/repos/bitbucketcloud_test.go +++ b/internal/repos/bitbucketcloud_test.go @@ -79,6 +79,20 @@ func TestBitbucketCloudSource_ListRepos(t *testing.T) { }, err: "", }, + { + name: "with access token", + assert: assertAllReposListed([]string{ + "/sourcegraph-source/src-cli", + "/sourcegraph-source/source-test", + }), + conf: &schema.BitbucketCloudConnection{ + AccessToken: os.Getenv("BITBUCKET_CLOUD_ACCESS_TOKEN"), + Teams: []string{ + "sourcegraph-source", + }, + }, + err: "", + }, } for _, tc := range testCases { diff --git a/internal/repos/clone_url.go b/internal/repos/clone_url.go index 8f1194ce3e6..f56a27696ae 100644 --- a/internal/repos/clone_url.go +++ b/internal/repos/clone_url.go @@ -163,7 +163,7 @@ func bitbucketServerCloneURL(repo *bitbucketserver.Repo, cfg *schema.BitbucketSe } // bitbucketCloudCloneURL returns the repository's Git remote URL with the configured -// Bitbucket Cloud app password inserted in the URL userinfo. +// Bitbucket Cloud app password or workspace access token inserted in the URL userinfo. func bitbucketCloudCloneURL(logger log.Logger, repo *bitbucketcloud.Repo, cfg *schema.BitbucketCloudConnection) string { if cfg.GitURLType == "ssh" { return fmt.Sprintf("git@%s:%s.git", cfg.Url, repo.FullName) @@ -186,7 +186,11 @@ func bitbucketCloudCloneURL(logger log.Logger, repo *bitbucketcloud.Repo, cfg *s return fallbackURL } - u.User = url.UserPassword(cfg.Username, cfg.AppPassword) + if cfg.AccessToken != "" { + u.User = url.UserPassword("x-token-auth", cfg.AccessToken) + } else { + u.User = url.UserPassword(cfg.Username, cfg.AppPassword) + } return u.String() } diff --git a/internal/repos/testdata/sources/BITBUCKETCLOUD-LIST-REPOS/with-access-token.yaml b/internal/repos/testdata/sources/BITBUCKETCLOUD-LIST-REPOS/with-access-token.yaml new file mode 100644 index 00000000000..d3a4a0a275b --- /dev/null +++ b/internal/repos/testdata/sources/BITBUCKETCLOUD-LIST-REPOS/with-access-token.yaml @@ -0,0 +1,143 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: {} + url: https://api.bitbucket.org/2.0/repositories/sourcegraph-source?pagelen=100 + method: GET + response: + body: '{"values": [{"type": "repository", "full_name": "sourcegraph-source/src-cli", + "links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/src-cli"}, "avatar": + {"href": "https://bytebucket.org/ravatar/%7B22bdacfc-eae7-4dcb-81c5-af096a93bd9b%7D?ts=default"}, + "pullrequests": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/pullrequests"}, + "commits": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/commits"}, + "forks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/forks"}, + "watchers": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/watchers"}, + "branches": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/refs/branches"}, + "tags": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/refs/tags"}, + "downloads": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/downloads"}, + "source": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/src"}, + "clone": [{"name": "https", "href": "https://2h1ehnddx9o2mwnng8plaqp56mb7aq@bitbucket.org/sourcegraph-source/src-cli.git"}, + {"name": "ssh", "href": "git@bitbucket.org:sourcegraph-source/src-cli.git"}], + "hooks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/src-cli/hooks"}}, + "name": "src-cli", "slug": "src-cli", "description": "", "scm": "git", "website": + null, "owner": {"display_name": "sourcegraph-source", "links": {"self": {"href": + "https://api.bitbucket.org/2.0/workspaces/%7B790592f7-4e5e-44a8-9ec6-8745876fe1c3%7D"}, + "avatar": {"href": "https://bitbucket.org/account/sourcegraph-source/avatar/"}, + "html": {"href": "https://bitbucket.org/%7B790592f7-4e5e-44a8-9ec6-8745876fe1c3%7D/"}}, + "type": "team", "uuid": "{790592f7-4e5e-44a8-9ec6-8745876fe1c3}", "username": + "sourcegraph-source"}, "workspace": {"type": "workspace", "uuid": "{790592f7-4e5e-44a8-9ec6-8745876fe1c3}", + "name": "sourcegraph-source", "slug": "sourcegraph-source", "links": {"avatar": + {"href": "https://bitbucket.org/workspaces/sourcegraph-source/avatar/?ts=1700076275"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/"}, "self": {"href": + "https://api.bitbucket.org/2.0/workspaces/sourcegraph-source"}}}, "is_private": + true, "project": {"type": "project", "key": "SOUR", "uuid": "{d4cb2804-9d30-4b8d-b880-8097b111375a}", + "name": "source", "links": {"self": {"href": "https://api.bitbucket.org/2.0/workspaces/sourcegraph-source/projects/SOUR"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/workspace/projects/SOUR"}, + "avatar": {"href": "https://bitbucket.org/account/user/sourcegraph-source/projects/SOUR/avatar/32?ts=1700076320"}}}, + "fork_policy": "no_public_forks", "created_on": "2023-11-15T19:25:20.076854+00:00", + "updated_on": "2023-11-15T19:25:20.911042+00:00", "size": 22185443, "language": + "", "uuid": "{22bdacfc-eae7-4dcb-81c5-af096a93bd9b}", "mainbranch": {"name": + "master", "type": "branch"}, "override_settings": {"default_merge_strategy": + true, "branching_model": true}, "parent": null, "has_issues": false, "has_wiki": + false}, {"type": "repository", "full_name": "sourcegraph-source/source-test", + "links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/source-test"}, "avatar": + {"href": "https://bytebucket.org/ravatar/%7Bdfeaae25-8168-466f-ade4-d07e6837dedf%7D?ts=default"}, + "pullrequests": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/pullrequests"}, + "commits": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/commits"}, + "forks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/forks"}, + "watchers": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/watchers"}, + "branches": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/refs/branches"}, + "tags": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/refs/tags"}, + "downloads": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/downloads"}, + "source": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/src"}, + "clone": [{"name": "https", "href": "https://2h1ehnddx9o2mwnng8plaqp56mb7aq@bitbucket.org/sourcegraph-source/source-test.git"}, + {"name": "ssh", "href": "git@bitbucket.org:sourcegraph-source/source-test.git"}], + "hooks": {"href": "https://api.bitbucket.org/2.0/repositories/sourcegraph-source/source-test/hooks"}}, + "name": "source-test", "slug": "source-test", "description": "", "scm": "git", + "website": null, "owner": {"display_name": "sourcegraph-source", "links": {"self": + {"href": "https://api.bitbucket.org/2.0/workspaces/%7B790592f7-4e5e-44a8-9ec6-8745876fe1c3%7D"}, + "avatar": {"href": "https://bitbucket.org/account/sourcegraph-source/avatar/"}, + "html": {"href": "https://bitbucket.org/%7B790592f7-4e5e-44a8-9ec6-8745876fe1c3%7D/"}}, + "type": "team", "uuid": "{790592f7-4e5e-44a8-9ec6-8745876fe1c3}", "username": + "sourcegraph-source"}, "workspace": {"type": "workspace", "uuid": "{790592f7-4e5e-44a8-9ec6-8745876fe1c3}", + "name": "sourcegraph-source", "slug": "sourcegraph-source", "links": {"avatar": + {"href": "https://bitbucket.org/workspaces/sourcegraph-source/avatar/?ts=1700076275"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/"}, "self": {"href": + "https://api.bitbucket.org/2.0/workspaces/sourcegraph-source"}}}, "is_private": + true, "project": {"type": "project", "key": "SOUR", "uuid": "{d4cb2804-9d30-4b8d-b880-8097b111375a}", + "name": "source", "links": {"self": {"href": "https://api.bitbucket.org/2.0/workspaces/sourcegraph-source/projects/SOUR"}, + "html": {"href": "https://bitbucket.org/sourcegraph-source/workspace/projects/SOUR"}, + "avatar": {"href": "https://bitbucket.org/account/user/sourcegraph-source/projects/SOUR/avatar/32?ts=1700076320"}}}, + "fork_policy": "no_public_forks", "created_on": "2023-11-21T13:39:54.600952+00:00", + "updated_on": "2023-11-21T13:39:57.299319+00:00", "size": 54954, "language": + "", "uuid": "{dfeaae25-8168-466f-ade4-d07e6837dedf}", "mainbranch": {"name": + "master", "type": "branch"}, "override_settings": {"default_merge_strategy": + true, "branching_model": true}, "parent": null, "has_issues": false, "has_wiki": + false}], "pagelen": 100, "size": 2, "page": 1}' + headers: + Cache-Control: + - private + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 21 Nov 2023 14:28:09 GMT + Etag: + - '"81bd5365c10a63e8359344c6deaad885"' + Server: + - envoy + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Vary: + - Authorization, Origin, cookie, user-context + X-Asap-Succeeded: + - "True" + X-B3-Spanid: + - 57e688568582f1b8 + X-B3-Traceid: + - 1d016bef27946a4e + X-Content-Type-Options: + - nosniff + X-Credential-Type: + - workspace_access_token + X-Dc-Location: + - Micros-3 + X-Envoy-Upstream-Service-Time: + - "250" + X-Frame-Options: + - SAMEORIGIN + X-Render-Time: + - "0.23119592666625977" + X-Request-Count: + - "1601" + X-Request-Id: + - 1d016bef27946a4e + X-Served-By: + - 3ce7dc13e690 + X-Static-Version: + - ba8afb91e693 + X-Trace-Id: + - 1d016bef27946a4e + X-Usage-Input-Ops: + - "0" + X-Usage-Output-Ops: + - "0" + X-Usage-System-Time: + - "0.004212" + X-Usage-User-Time: + - "0.125926" + X-Used-Mesh: + - "False" + X-Version: + - ba8afb91e693 + X-View-Name: + - bitbucket.apps.repo2.api.v20.repo.RepositoriesHandler + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/internal/types/secret.go b/internal/types/secret.go index 95a3b6ee6b4..bd0f4b2ed08 100644 --- a/internal/types/secret.go +++ b/internal/types/secret.go @@ -66,6 +66,7 @@ func (e *ExternalService) RedactedConfig(ctx context.Context) (string, error) { es.redactString(c.Token, "token") case *schema.BitbucketCloudConnection: es.redactString(c.AppPassword, "appPassword") + es.redactString(c.AccessToken, "accessToken") case *schema.AWSCodeCommitConnection: es.redactString(c.SecretAccessKey, "secretAccessKey") es.redactString(c.GitCredentials.Password, "gitCredentials", "password") @@ -184,10 +185,21 @@ func (e *ExternalService) UnredactConfig(ctx context.Context, old *ExternalServi es.unredactString(c.Token, o.Token, "token") case *schema.BitbucketCloudConnection: o := oldCfg.(*schema.BitbucketCloudConnection) - es.unredactString(c.AppPassword, o.AppPassword, "appPassword") if c.Url != o.Url { - return errCodeHostIdentityChanged{"apiUrl", "appPassword"} + var redactedProperty string + if c.AppPassword == RedactedSecret { + redactedProperty = "appPassword" + } + if c.AccessToken == RedactedSecret { + redactedProperty = "accessToken" + } + + if redactedProperty != "" { + return errCodeHostIdentityChanged{"apiUrl", redactedProperty} + } } + es.unredactString(c.AppPassword, o.AppPassword, "appPassword") + es.unredactString(c.AccessToken, o.AccessToken, "accessToken") case *schema.AWSCodeCommitConnection: o := oldCfg.(*schema.AWSCodeCommitConnection) es.unredactString(c.SecretAccessKey, o.SecretAccessKey, "secretAccessKey") diff --git a/schema/bitbucket_cloud.schema.json b/schema/bitbucket_cloud.schema.json index 42de42d3f6f..3e06ed6ad14 100644 --- a/schema/bitbucket_cloud.schema.json +++ b/schema/bitbucket_cloud.schema.json @@ -6,7 +6,26 @@ "allowComments": true, "type": "object", "additionalProperties": false, - "required": ["url", "username", "appPassword"], + "required": ["url"], + "oneOf": [ + { + "allOf": [ + { + "required": ["accessToken"] + }, + { + "not": { "required": ["username"] } + }, + { + "not": { "required": ["appPassword"] } + } + ] + }, + { + "required": ["username", "appPassword"], + "not": { "required": ["accessToken"] } + } + ], "properties": { "url": { "description": "URL of Bitbucket Cloud, such as https://bitbucket.org. Generally, admin should not modify the value of this option because Bitbucket Cloud is a public hosting platform.", @@ -72,6 +91,10 @@ "description": "The app password to use when authenticating to the Bitbucket Cloud. Also set the corresponding \"username\" field.", "type": "string" }, + "accessToken": { + "description": "The workspace access token to use when authenticating with Bitbucket Cloud.", + "type": "string" + }, "gitURLType": { "description": "The type of Git URLs to use for cloning and fetching Git repositories on this Bitbucket Cloud.\n\nIf \"http\", Sourcegraph will access Bitbucket Cloud repositories using Git URLs of the form https://bitbucket.org/myteam/myproject.git.\n\nIf \"ssh\", Sourcegraph will access Bitbucket Cloud repositories using Git URLs of the form git@bitbucket.org:myteam/myproject.git. See the documentation for how to provide SSH private keys and known_hosts: https://docs.sourcegraph.com/admin/repo/auth#repositories-that-need-http-s-or-ssh-authentication.", "type": "string", diff --git a/schema/schema.go b/schema/schema.go index b452c8adb41..05af4959017 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -301,10 +301,12 @@ type BitbucketCloudAuthorization struct { // BitbucketCloudConnection description: Configuration for a connection to Bitbucket Cloud. type BitbucketCloudConnection struct { + // AccessToken description: The workspace access token to use when authenticating with Bitbucket Cloud. + AccessToken string `json:"accessToken,omitempty"` // ApiURL description: The API URL of Bitbucket Cloud, such as https://api.bitbucket.org. Generally, admin should not modify the value of this option because Bitbucket Cloud is a public hosting platform. ApiURL string `json:"apiURL,omitempty"` // AppPassword description: The app password to use when authenticating to the Bitbucket Cloud. Also set the corresponding "username" field. - AppPassword string `json:"appPassword"` + AppPassword string `json:"appPassword,omitempty"` // Authorization description: If non-null, enforces Bitbucket Cloud repository permissions. This requires that there is an item in the [site configuration json](https://docs.sourcegraph.com/admin/config/site_config#auth-providers) `auth.providers` field, of type "bitbucketcloud" with the same `url` field as specified in this `BitbucketCloudConnection`. Authorization *BitbucketCloudAuthorization `json:"authorization,omitempty"` // Exclude description: A list of repositories to never mirror from Bitbucket Cloud. Takes precedence over "teams" configuration. @@ -332,7 +334,7 @@ type BitbucketCloudConnection struct { // Url description: URL of Bitbucket Cloud, such as https://bitbucket.org. Generally, admin should not modify the value of this option because Bitbucket Cloud is a public hosting platform. Url string `json:"url"` // Username description: The username to use when authenticating to the Bitbucket Cloud. Also set the corresponding "appPassword" field. - Username string `json:"username"` + Username string `json:"username,omitempty"` // WebhookSecret description: A shared secret used to authenticate incoming webhooks (minimum 12 characters). WebhookSecret string `json:"webhookSecret,omitempty"` }