In the previous post, I detailed how to transition users and groups to Bitbucket Cloud, ensuring that your team’s collaboration structure remains intact in the cloud environment. Building on that foundation, this post will dive into migrating repository permissions, a critical step to maintain your project’s security and access controls in Bitbucket Cloud.
Introduction
Migrating repository permissions is a crucial task that ensures your team members have appropriate access to projects and repositories in Bitbucket Cloud. This process involves mapping permissions from your on-premises Bitbucket Server (Data Center) to Bitbucket Cloud. Our script simplifies this process, automating the transfer of user and group permissions to their new cloud environment.
This guide assumes that you’ve already transferred users and groups to Bitbucket Cloud, as detailed in previous posts.
Script Overview
The provided Python script is designed to fetch permission settings from Bitbucket Server and apply them to the corresponding entities in Bitbucket Cloud. The script handles:
- Project-level permissions for users and groups
- Repository-level permissions for users and groups
It makes use of the Bitbucket Cloud and Server APIs to retrieve and set permissions based on your current setup.
Pre-Requisites
- Python installed on your machine.
- Administrative access to both your Bitbucket Server and Cloud accounts.
- Execution of the previous script to migrate users and groups.
How the Script Works
- Fetching Group Slugs: The script begins by retrieving slugs for all groups in your Bitbucket Cloud workspace, essential for setting group permissions.
- Mapping Permissions: The script maps Bitbucket Server permissions to their Bitbucket Cloud equivalents.
- Applying Project Permissions: The script iterates over each project, applying user and group permissions according to the mappings.
- Applying Repository Permissions: Similar to project permissions, the script applies user and group permissions at the repository level.
Execution Steps
- Ensure Script Setup: Verify that your
config.pyand environment are correctly set up as per the prerequisites. - Run the Script: Execute the script. Monitor the logging output for progress and any potential errors.
- Verify Permissions in Bitbucket Cloud: Once the script completes, manually review several projects and repositories in Bitbucket Cloud to confirm that permissions have been correctly applied.
import csv
import requests
import os
import logging
from requests.auth import HTTPBasicAuth
from config import cloud, on_prem
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def which_project_permission(permission):
return {
"PROJECT_WRITE": "write",
"PROJECT_READ": "read",
"PROJECT_ADMIN": "admin",
}.get(permission, "")
def which_repo_permission(permission):
return {
"REPO_WRITE": "write",
"REPO_READ": "read",
"REPO_ADMIN": "admin",
}.get(permission, "")
def get_group_slugs(workspace_id):
url = f"https://api.bitbucket.org/1.0/groups/{workspace_id}/"
auth = HTTPBasicAuth(cloud['username'], cloud['token'])
try:
response = requests.get(url, auth=auth)
group_slugs = {}
if response.ok:
for group in response.json():
group_slugs[group['name']] = group['slug']
logging.info(f"Retrieved group slugs for workspace: {workspace_id}")
else:
logging.error(f"Failed to retrieve group slugs for workspace: {workspace_id}. Status code: {response.status_code}")
return group_slugs
except requests.exceptions.RequestException as e:
logging.error(f"Error retrieving group slugs: {e}")
return {}
script_location = os.path.dirname(os.path.abspath(__file__))
bitbucket_server_repositories = os.path.join(script_location, on_prem["bitbucket_server_repositories"])
logging.info("Fetching group slugs from Bitbucket API...")
group_slugs = get_group_slugs(cloud['workspace'])
def get_uuid_from_user(displayName):
users_file = os.path.join(script_location, "bitbucket_users_match.csv")
with open(users_file, mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for row in csv_reader:
if row['cloud_display_name'] == displayName:
return row['cloud_uuid']
return None
project_keys_set = set()
with open(bitbucket_server_repositories, mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for row in csv_reader:
project_keys_set.add(row['project_key'])
logging.info("Processing project permissions...")
for project_key in project_keys_set:
users_response = requests.get(
f"{on_prem['base_url']}/rest/api/1.0/projects/{project_key}/permissions/users",
auth = HTTPBasicAuth(on_prem['username'], on_prem['password']),
headers = {"Accept": "application/json"} # Request headers
).json()
for user in users_response['values']:
mapped_permission = which_project_permission(user['permission'])
if mapped_permission:
user_uuid = get_uuid_from_user(user['user']['displayName'])
if user_uuid != '':
response = requests.request(
'PUT',
f"https://api.bitbucket.org/2.0/workspaces/{cloud['workspace']}/projects/{project_key}/permissions-config/users/{user_uuid}",
auth = HTTPBasicAuth(cloud['username'], cloud['token']),
headers = {"Accept": "application/json"},
json={"permission": mapped_permission}
)
groups_response = requests.get(
f"{on_prem['base_url']}/rest/api/1.0/projects/{project_key}/permissions/groups",
auth = HTTPBasicAuth(on_prem['username'], on_prem['password']),
headers = {"Accept": "application/json"}
).json()
for group in groups_response['values']:
mapped_permission = which_project_permission(group['permission'])
if mapped_permission:
group_slug = group_slugs.get(group['group']['name'])
if group_slug != '':
response = requests.request(
'PUT',
f"https://api.bitbucket.org/2.0/workspaces/{cloud['workspace']}/projects/{project_key}/permissions-config/groups/{group_slug}",
auth = HTTPBasicAuth(cloud['username'], cloud['token']),
headers = {"Accept": "application/json"},
data={"permission": mapped_permission}
)
logging.info(f"Processed permissions for project: {project_key}")
#repo level
logging.info("Processing repository permissions...")
with open(bitbucket_server_repositories, mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for row in csv_reader:
repo_slug = row['slug']
project_key = row['project_key']
users_response = requests.get(
f"{on_prem['base_url']}/rest/api/1.0/projects/{project_key}/repos/{repo_slug}/permissions/users",
auth = HTTPBasicAuth(on_prem['username'], on_prem['password']),
headers = {"Accept": "application/json"} # Request headers
).json()
for user in users_response['values']:
mapped_permission = which_project_permission(user['permission'])
if mapped_permission:
user_uuid = get_uuid_from_user(user['user']['displayName'])
if user_uuid != '':
response = requests.request(
'PUT',
f"https://api.bitbucket.org/2.0/repositories/{cloud['workspace']}/{repo_slug}/permissions-config/users/{user_uuid}",
auth = HTTPBasicAuth(cloud['username'], cloud['token']),
headers = {"Accept": "application/json"},
json={"permission": mapped_permission}
)
groups_response = requests.get(
f"{on_prem['base_url']}/rest/api/1.0/projects/{project_key}/repos/{repo_slug}/permissions/groups",
auth = HTTPBasicAuth(on_prem['username'], on_prem['password']),
headers = {"Accept": "application/json"}
).json()
for group in groups_response['values']:
mapped_permission = which_project_permission(group['permission'])
if mapped_permission:
group_slug = group_slugs.get(group['group']['name'])
if group_slug != '':
response = requests.request(
'PUT',
f"https://api.bitbucket.org/2.0/repositories/{cloud['workspace']}/{repo_slug}/permissions-config/groups/{group_slug}",
auth = HTTPBasicAuth(cloud['username'], cloud['token']),
headers = {"Accept": "application/json"},
data={"permission": mapped_permission}
)
logging.info(f"Processed permissions for repository: {repo_slug}")
logging.info("Permissions processing complete.")
Conclusion
Migrating repository permissions does not have to be a daunting task. With this automated script, you can efficiently transfer permissions, ensuring your team’s access control policies remain effective in Bitbucket Cloud. This guide, combined with our previous post on migrating users and groups, provides you with a comprehensive approach to secure and seamless migration to Bitbucket Cloud.