Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for bitbucket workspace token authentication #508

Merged
merged 4 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/other.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ func getToken(flag *flag.FlagSet) (string, error) {
token = ght
} else if ght := os.Getenv("BITBUCKET_CLOUD_APP_PASSWORD"); ght != "" {
token = ght
} else if ght := os.Getenv("BITBUCKET_CLOUD_WORKSPACE_TOKEN"); ght != "" {
token = ght
}
}

if token == "" {
return "", errors.New("either the --token flag or the GITHUB_TOKEN/GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_SERVER_TOKEN/BITBUCKET_CLOUD_APP_PASSWORD environment variable has to be set")
return "", errors.New("either the --token flag or the GITHUB_TOKEN/GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_SERVER_TOKEN/BITBUCKET_CLOUD_APP_PASSWORD/BITBUCKET_CLOUD_WORKSPACE_TOKEN environment variable has to be set")
}

return token, nil
Expand Down
6 changes: 4 additions & 2 deletions cmd/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ func configurePlatform(cmd *cobra.Command) {
flags.StringP("base-url", "g", "", "Base URL of the target platform, needs to be changed for GitHub enterprise, a self-hosted GitLab instance, Gitea or BitBucket.")
flags.BoolP("insecure", "", false, "Insecure controls whether a client verifies the server certificate chain and host name. Used only for Bitbucket server.")
flags.StringP("username", "u", "", "The Bitbucket server username.")
flags.StringP("token", "T", "", "The personal access token for the targeting platform. Can also be set using the GITHUB_TOKEN/GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_SERVER_TOKEN/BITBUCKET_CLOUD_APP_PASSWORD environment variable.")
flags.StringP("token", "T", "", "The personal access token for the targeting platform. Can also be set using the GITHUB_TOKEN/GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_SERVER_TOKEN/BITBUCKET_CLOUD_APP_PASSWORD/BITBUCKET_CLOUD_WORKSPACE_TOKEN environment variable.")
flags.StringP("authtype", "", "", "The authentication type. Either app-password or workspace-token. Used only for Bitbucket cloud.")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be defined as constant values and should error (or succeed) in the parsing. There is also autocompletion that could be done. Please see the conflict-strategy option for reference and feel free to ask if there is any uncertainties.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having no default option here makes this not backwards compatible for no good reason.

I see three options here:

  1. Set the default value to app-password to keep backwards compatability
  2. Set the default value to workspace-token if this is the preferred method of authentication. This would break backwards compatibility, but because of a good reason which could be ok because of the state of the BBC implementation.
  3. The most extreme approach would be to remove password authentication altogether. But if there is no real good reason for people to use it, (meaning they could always use tokens instead,) I would be in favor of this option.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also minor comment on the actual name. Should probably be auth-type to match with other names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comments! And yes I am part of the Atlassian team.

I updated the auth-type flag and tried to copy the conflict-strategy pattern. Please let me know if I should structure anything differently.
For the default option, I decided to use app-password since workspace tokens are a premium feature, so many users will still need to use app password.


flags.StringSliceP("org", "O", nil, "The name of a GitHub organization. All repositories in that organization will be used.")
flags.StringSliceP("group", "G", nil, "The name of a GitLab organization. All repositories in that group will be used.")
Expand Down Expand Up @@ -294,6 +295,7 @@ func createBitbucketCloudClient(flag *flag.FlagSet, verifyFlags bool) (multigitt
sshAuth, _ := flag.GetBool("ssh-auth")
fork, _ := flag.GetBool("fork")
newOwner, _ := flag.GetString("fork-owner")
authType, _ := flag.GetString("authtype")

if verifyFlags && len(workspaces) == 0 && len(users) == 0 && len(repos) == 0 {
return nil, errors.New("no workspace, user or repository set")
Expand All @@ -308,7 +310,7 @@ func createBitbucketCloudClient(flag *flag.FlagSet, verifyFlags bool) (multigitt
return nil, err
}

vc, err := bitbucketcloud.New(username, token, repos, workspaces, users, fork, sshAuth, newOwner)
vc, err := bitbucketcloud.New(username, token, repos, workspaces, users, fork, sshAuth, newOwner, authType)
if err != nil {
return nil, err
}
Expand Down
16 changes: 11 additions & 5 deletions docs/README.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,21 @@ Do you have a nice script that might be useful to others? Please create a PR tha

_note: bitbucket cloud support is currently in Beta_

In order to use bitbucket cloud you will need to create and use an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/). The app password you create needs sufficient permissions so ensure you grant it Read and Write access to projects, repositories and pull requests and at least Read access to your account and workspace membership.
In order to use bitbucket cloud you will need to create and use an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) or [Workspace Token](https://support.atlassian.com/bitbucket-cloud/docs/access-tokens/). The app password or workspace token you create needs sufficient permissions so ensure you grant it Read and Write access to projects, repositories and pull requests and at least Read access to your account and workspace membership.

You will need to configure the bitbucket workspace using the `org` option for multi-gitter for the repositories you want to make changes to e.g. `multi-gitter run examples/go/upgrade-go-version.sh -u your_username --org "your_workspace"`
You will need to configure the bitbucket workspace using the `org` option for multi-gitter for the repositories you want to make changes to. You will also need to configure the authentication method using the `authtype` flag e.g. `multi-gitter run examples/go/upgrade-go-version.sh -u your_username --org "your_workspace" --authtype app-password`

### Example
Here is an example of using the command line options to run a script from the `examples/` directory and make pull-requests for a few repositories in a specified workspace.
Here is an example of using the command line options to run a script from the `examples/` directory and make pull-requests for a few repositories in a specified workspace, using app password authentication.
```shell
export BITBUCKET_CLOUD_APP_PASSWORD="your_app_password"
multi-gitter run examples/go/upgrade-go-version.sh -u your_username --org "your_workspace" --repo "your_first_repository,your_second_repository" --platform bitbucket_cloud -m "your_commit_message" -B your_branch_name
multi-gitter run examples/go/upgrade-go-version.sh -u your_username --org "your_workspace" --repo "your_first_repository,your_second_repository" --platform bitbucket_cloud -m "your_commit_message" -B your_branch_name --authtype app-password
```

Here is an example of running the script using workspace token authentication.
```shell
export BITBUCKET_CLOUD_WORKSPACE_TOKEN="your_workspace_token"
multi-gitter run examples/go/upgrade-go-version.sh -u your_username --org "your_workspace" --repo "your_first_repository,your_second_repository" --platform bitbucket_cloud -m "your_commit_message" -B your_branch_name --authtype workspace-token
```

### Bitbucket Cloud Limitations
Expand All @@ -165,4 +171,4 @@ We also only support modifying a single workspace, any additional workspaces pas

We also have noticed the performance is slower with larger workspaces and we expect to resolve this when we add support for projects to make filtering repositories by project faster.

</details>
</details>
35 changes: 28 additions & 7 deletions internal/scm/bitbucketcloud/bitbucket_cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
token string
sshAuth bool
newOwner string
authType string
httpClient *http.Client
bbClient *bitbucket.Client
}

func New(username string, token string, repositories []string, workspaces []string, users []string, fork bool, sshAuth bool,
newOwner string) (*BitbucketCloud, error) {
newOwner string, authType string) (*BitbucketCloud, error) {
if strings.TrimSpace(token) == "" {
return nil, errors.New("bearer token is empty")
}
Expand All @@ -44,10 +45,20 @@
bitbucketCloud.token = token
bitbucketCloud.sshAuth = sshAuth
bitbucketCloud.newOwner = newOwner
bitbucketCloud.authType = authType
bitbucketCloud.httpClient = &http.Client{
Transport: internalHTTP.LoggingRoundTripper{},
}
bitbucketCloud.bbClient = bitbucket.NewBasicAuth(username, token)

if authType == "app-password" {

Check failure on line 53 in internal/scm/bitbucketcloud/bitbucket_cloud.go

View workflow job for this annotation

GitHub Actions / golangci-lint

[golangci] reported by reviewdog 🐶 string `app-password` has 3 occurrences, make it a constant (goconst) Raw Output: internal/scm/bitbucketcloud/bitbucket_cloud.go:53:17: string `app-password` has 3 occurrences, make it a constant (goconst) if authType == "app-password" { ^
// Authenticate using app password
bitbucketCloud.bbClient = bitbucket.NewBasicAuth(username, token)
} else if authType == "workspace-token" {
// Authenticate using workspace token
bitbucketCloud.bbClient = bitbucket.NewOAuthbearerToken(token)
} else {
return nil, errors.New("Please enter a valid value for authtype (app-password or workspace-token)")
}

return bitbucketCloud, nil
}
Expand All @@ -59,16 +70,21 @@
Owner: bbc.workspaces[0],
RepoSlug: bbcRepo.name,
}
currentUser, err := bbc.bbClient.User.Profile()
if err != nil {
return nil, err
var currentUserUUID string
if bbc.authType == "app-password" {
currentUser, err := bbc.bbClient.User.Profile()
if err != nil {
return nil, err
}
currentUserUUID = currentUser.Uuid
}

defaultReviewers, err := bbc.bbClient.Repositories.Repository.ListEffectiveDefaultReviewers(repoOptions)
if err != nil {
return nil, err
}
for _, reviewer := range defaultReviewers.EffectiveDefaultReviewers {
if currentUser.Uuid != reviewer.User.Uuid {
if currentUserUUID != reviewer.User.Uuid {
newPR.Reviewers = append(newPR.Reviewers, reviewer.User.Uuid)
}
}
Expand Down Expand Up @@ -351,7 +367,12 @@
return nil, err
}

parsedURL.User = url.UserPassword(bbc.username, bbc.token)
if bbc.authType == "app-password" {
parsedURL.User = url.UserPassword(bbc.username, bbc.token)
} else if bbc.authType == "workspace-token" {
parsedURL.User = url.UserPassword("x-token-auth", bbc.token)
}

cloneURL = parsedURL.String()
}

Expand Down
Loading