Merge pull request #207 from coreos-inc/squashperm

Have the fetch tag dialog show a warning for robot accounts without access
This commit is contained in:
josephschorr 2015-07-02 10:23:14 +03:00
commit cb238f8764
5 changed files with 108 additions and 2 deletions

View file

@ -1201,6 +1201,12 @@ def update_email(user, new_email, auto_verify=False):
def get_all_user_permissions(user): def get_all_user_permissions(user):
return _get_user_repo_permissions(user)
def get_user_repo_permissions(user, repo):
return _get_user_repo_permissions(user, limit_to_repository_obj=repo)
def _get_user_repo_permissions(user, limit_to_repository_obj=None):
UserThroughTeam = User.alias() UserThroughTeam = User.alias()
base_query = (RepositoryPermission base_query = (RepositoryPermission
@ -1211,6 +1217,9 @@ def get_all_user_permissions(user):
.join(Namespace, on=(Repository.namespace_user == Namespace.id)) .join(Namespace, on=(Repository.namespace_user == Namespace.id))
.switch(RepositoryPermission)) .switch(RepositoryPermission))
if limit_to_repository_obj is not None:
base_query = base_query.where(RepositoryPermission.repository == limit_to_repository_obj)
direct = (base_query direct = (base_query
.clone() .clone()
.join(User) .join(User)

View file

@ -6,7 +6,8 @@ from flask import request
from app import avatar from app import avatar
from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource, from endpoints.api import (resource, nickname, require_repo_admin, RepositoryParamResource,
log_action, request_error, validate_json_request, path_param) log_action, request_error, validate_json_request, path_param,
NotFound)
from data import model from data import model
@ -96,6 +97,30 @@ class RepositoryUserPermissionList(RepositoryParamResource):
} }
@resource('/v1/repository/<repopath:repository>/permissions/user/<username>/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, repository, username):
""" Get the fetch the permission for the specified user. """
user = model.get_user(username)
if not user:
raise NotFound
repo = model.get_repository(namespace, repository)
if not repo:
raise NotFound
permissions = list(model.get_user_repo_permissions(user, repo))
return {
'permissions': [role_view(permission) for permission in permissions]
}
@resource('/v1/repository/<repopath:repository>/permissions/user/<username>') @resource('/v1/repository/<repopath:repository>/permissions/user/<username>')
@path_param('repository', 'The full path of the repository. e.g. namespace/name') @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') @path_param('username', 'The username of the user to which the permission applies')

View file

@ -56,6 +56,13 @@
</table> </table>
<div class="cor-loader-inline" ng-if="currentEntity && !currentRobot"></div> <div class="cor-loader-inline" ng-if="currentEntity && !currentRobot"></div>
<div class="co-alert co-alert-warning"
ng-if="currentRobotHasPermission === false">
Warning: Robot account <strong>{{ currentRobot.name }}</strong> does not have
read permission on this repository, so the command below will fail with an authorization error.
</div>
<div ng-if="getCommand(currentFormat, currentRobot)"> <div ng-if="getCommand(currentFormat, currentRobot)">
Command: Command:
<pre class="command">{{ getCommand(currentFormat, currentRobot) }}</pre> <pre class="command">{{ getCommand(currentFormat, currentRobot) }}</pre>

View file

@ -18,6 +18,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
$scope.currentEntity = null; $scope.currentEntity = null;
$scope.currentRobot = null; $scope.currentRobot = null;
$scope.formats = []; $scope.formats = [];
$scope.currentRobotHasPermission = null;
UserService.updateUserIn($scope, updateFormats); UserService.updateUserIn($scope, updateFormats);
@ -58,6 +59,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
} }
$scope.currentRobot = null; $scope.currentRobot = null;
$scope.currentRobotHasPermission = null;
var parts = entity.name.split('+'); var parts = entity.name.split('+');
var namespace = parts[0]; var namespace = parts[0];
@ -71,6 +73,15 @@ angular.module('quay').directive('fetchTagDialog', function () {
ApiService.getRobot(orgname, null, params).then(function(resp) { ApiService.getRobot(orgname, null, params).then(function(resp) {
$scope.currentRobot = resp; $scope.currentRobot = resp;
}, ApiService.errorDisplay('Cannot download robot token')); }, ApiService.errorDisplay('Cannot download robot token'));
var permParams = {
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
'username': entity.name
};
ApiService.getUserTransitivePermission(null, permParams).then(function(resp) {
$scope.currentRobotHasPermission = resp['permissions'].length > 0;
});
}); });
$scope.getCommand = function(format, robot) { $scope.getCommand = function(format, robot) {
@ -106,6 +117,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
$scope.currentFormat = null; $scope.currentFormat = null;
$scope.currentEntity = null; $scope.currentEntity = null;
$scope.currentRobot = null; $scope.currentRobot = null;
$scope.currentRobotHasPermission = null;
$scope.clearCounter++; $scope.clearCounter++;

View file

@ -43,7 +43,8 @@ from endpoints.api.organization import (OrganizationList, OrganizationMember,
OrganizationApplicationResetClientSecret) OrganizationApplicationResetClientSecret)
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission, from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
RepositoryTeamPermissionList, RepositoryUserPermissionList) RepositoryTeamPermissionList, RepositoryUserPermissionList,
RepositoryUserTransitivePermission)
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement, from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
SuperUserSendRecoveryEmail, ChangeLog, SuperUserSendRecoveryEmail, ChangeLog,
SuperUserOrganizationManagement, SuperUserOrganizationList) SuperUserOrganizationManagement, SuperUserOrganizationList)
@ -728,6 +729,58 @@ class TestTeamMemberListBuynlargeOwners(ApiTestCase):
self._run_test('GET', 200, 'devtable', None) self._run_test('GET', 200, 'devtable', None)
class TestRepositoryUserTransitivePermissionA2o9PublicPublicrepo(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(RepositoryUserTransitivePermission, username="A2O9", repository="public/publicrepo")
def test_get_anonymous(self):
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
def test_get_reader(self):
self._run_test('GET', 403, 'reader', None)
def test_get_devtable(self):
self._run_test('GET', 403, 'devtable', None)
class TestRepositoryUserTransitivePermissionA2o9DevtableShared(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(RepositoryUserTransitivePermission, username="A2O9", repository="devtable/shared")
def test_get_anonymous(self):
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
def test_get_reader(self):
self._run_test('GET', 403, 'reader', None)
def test_get_devtable(self):
self._run_test('GET', 404, 'devtable', None)
class TestRepositoryUserTransitivePermissionA2o9BuynlargeOrgrepo(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(RepositoryUserTransitivePermission, username="A2O9", repository="buynlarge/orgrepo")
def test_get_anonymous(self):
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
def test_get_reader(self):
self._run_test('GET', 403, 'reader', None)
def test_get_devtable(self):
self._run_test('GET', 404, 'devtable', None)
class TestRepositoryUserPermissionA2o9PublicPublicrepo(ApiTestCase): class TestRepositoryUserPermissionA2o9PublicPublicrepo(ApiTestCase):
def setUp(self): def setUp(self):
ApiTestCase.setUp(self) ApiTestCase.setUp(self)