""" Manage repository permissions. """ import logging from flask import request from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource, log_action, request_error, validate_json_request, path_param) from endpoints.exception import NotFound from permission_models_pre_oci import pre_oci_model as model from permission_models_interface import DeleteException, SaveException logger = logging.getLogger(__name__) @resource('/v1/repository//permissions/team/') @path_param('repository', 'The full path of the repository. e.g. namespace/name') class RepositoryTeamPermissionList(RepositoryParamResource): """ Resource for repository team permissions. """ @require_repo_admin @nickname('listRepoTeamPermissions') def get(self, namespace_name, repository_name): """ List all team permission. """ repo_perms = model.get_repo_permissions_by_team(namespace_name, repository_name) return { 'permissions': {repo_perm.team_name: repo_perm.to_dict() for repo_perm in repo_perms} } @resource('/v1/repository//permissions/user/') @path_param('repository', 'The full path of the repository. e.g. namespace/name') class RepositoryUserPermissionList(RepositoryParamResource): """ Resource for repository user permissions. """ @require_repo_admin @nickname('listRepoUserPermissions') def get(self, namespace_name, repository_name): """ List all user permissions. """ perms = model.get_repo_permissions_by_user(namespace_name, repository_name) return {'permissions': {p.username: p.to_dict() for p in perms}} @resource('/v1/repository//permissions/user//transitive') @path_param('repository', 'The full path of the repository. e.g. namespace/name') @path_param('username', 'The username of the user to which the permissions apply') class RepositoryUserTransitivePermission(RepositoryParamResource): """ Resource for retrieving whether a user has access to a repository, either directly or via a team. """ @require_repo_admin @nickname('getUserTransitivePermission') def get(self, namespace_name, repository_name, username): """ Get the fetch the permission for the specified user. """ roles = model.get_repo_roles(username, namespace_name, repository_name) if not roles: raise NotFound return { 'permissions': [r.to_dict() for r in roles] } @resource('/v1/repository//permissions/user/') @path_param('repository', 'The full path of the repository. e.g. namespace/name') @path_param('username', 'The username of the user to which the permission applies') class RepositoryUserPermission(RepositoryParamResource): """ Resource for managing individual user permissions. """ schemas = { 'UserPermission': { 'type': 'object', 'description': 'Description of a user permission.', 'required': [ 'role', ], 'properties': { 'role': { 'type': 'string', 'description': 'Role to use for the user', 'enum': [ 'read', 'write', 'admin', ], }, }, }, } @require_repo_admin @nickname('getUserPermissions') def get(self, namespace_name, repository_name, username): """ Get the permission for the specified user. """ logger.debug('Get repo: %s/%s permissions for user %s', namespace_name, repository_name, username) perm = model.get_repo_permission_for_user(username, namespace_name, repository_name) return perm.to_dict() @require_repo_admin @nickname('changeUserPermissions') @validate_json_request('UserPermission') def put(self, namespace_name, repository_name, username): # Also needs to respond to post """ Update the perimssions for an existing repository. """ new_permission = request.get_json() logger.debug('Setting permission to: %s for user %s', new_permission['role'], username) try: perm = model.set_repo_permission_for_user(username, namespace_name, repository_name, new_permission['role']) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action('change_repo_permission', namespace_name, {'username': username, 'repo': repository_name, 'namespace': namespace_name, 'role': new_permission['role']}, repo_name=repository_name) return resp, 200 @require_repo_admin @nickname('deleteUserPermissions') def delete(self, namespace_name, repository_name, username): """ Delete the permission for the user. """ try: model.delete_repo_permission_for_user(username, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action('delete_repo_permission', namespace_name, {'username': username, 'repo': repository_name, 'namespace': namespace_name}, repo_name=repository_name) return '', 204 @resource('/v1/repository//permissions/team/') @path_param('repository', 'The full path of the repository. e.g. namespace/name') @path_param('teamname', 'The name of the team to which the permission applies') class RepositoryTeamPermission(RepositoryParamResource): """ Resource for managing individual team permissions. """ schemas = { 'TeamPermission': { 'type': 'object', 'description': 'Description of a team permission.', 'required': [ 'role', ], 'properties': { 'role': { 'type': 'string', 'description': 'Role to use for the team', 'enum': [ 'read', 'write', 'admin', ], }, }, }, } @require_repo_admin @nickname('getTeamPermissions') def get(self, namespace_name, repository_name, teamname): """ Fetch the permission for the specified team. """ logger.debug('Get repo: %s/%s permissions for team %s', namespace_name, repository_name, teamname) role = model.get_repo_role_for_team(teamname, namespace_name, repository_name) return role.to_dict() @require_repo_admin @nickname('changeTeamPermissions') @validate_json_request('TeamPermission') def put(self, namespace_name, repository_name, teamname): """ Update the existing team permission. """ new_permission = request.get_json() logger.debug('Setting permission to: %s for team %s', new_permission['role'], teamname) try: perm = model.set_repo_permission_for_team(teamname, namespace_name, repository_name, new_permission['role']) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action('change_repo_permission', namespace_name, {'team': teamname, 'repo': repository_name, 'role': new_permission['role']}, repo_name=repository_name) return resp, 200 @require_repo_admin @nickname('deleteTeamPermissions') def delete(self, namespace_name, repository_name, teamname): """ Delete the permission for the specified team. """ try: model.delete_repo_permission_for_team(teamname, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action('delete_repo_permission', namespace_name, {'team': teamname, 'repo': repository_name}, repo_name=repository_name) return '', 204