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:
commit
cb238f8764
5 changed files with 108 additions and 2 deletions
|
@ -1201,6 +1201,12 @@ def update_email(user, new_email, auto_verify=False):
|
|||
|
||||
|
||||
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()
|
||||
|
||||
base_query = (RepositoryPermission
|
||||
|
@ -1211,6 +1217,9 @@ def get_all_user_permissions(user):
|
|||
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
|
||||
.switch(RepositoryPermission))
|
||||
|
||||
if limit_to_repository_obj is not None:
|
||||
base_query = base_query.where(RepositoryPermission.repository == limit_to_repository_obj)
|
||||
|
||||
direct = (base_query
|
||||
.clone()
|
||||
.join(User)
|
||||
|
|
|
@ -6,7 +6,8 @@ from flask import request
|
|||
|
||||
from app import avatar
|
||||
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
|
||||
|
||||
|
||||
|
@ -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>')
|
||||
@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')
|
||||
|
|
|
@ -56,6 +56,13 @@
|
|||
</table>
|
||||
|
||||
<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)">
|
||||
Command:
|
||||
<pre class="command">{{ getCommand(currentFormat, currentRobot) }}</pre>
|
||||
|
|
|
@ -18,6 +18,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
|
|||
$scope.currentEntity = null;
|
||||
$scope.currentRobot = null;
|
||||
$scope.formats = [];
|
||||
$scope.currentRobotHasPermission = null;
|
||||
|
||||
UserService.updateUserIn($scope, updateFormats);
|
||||
|
||||
|
@ -58,6 +59,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
|
|||
}
|
||||
|
||||
$scope.currentRobot = null;
|
||||
$scope.currentRobotHasPermission = null;
|
||||
|
||||
var parts = entity.name.split('+');
|
||||
var namespace = parts[0];
|
||||
|
@ -71,6 +73,15 @@ angular.module('quay').directive('fetchTagDialog', function () {
|
|||
ApiService.getRobot(orgname, null, params).then(function(resp) {
|
||||
$scope.currentRobot = resp;
|
||||
}, 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) {
|
||||
|
@ -106,6 +117,7 @@ angular.module('quay').directive('fetchTagDialog', function () {
|
|||
$scope.currentFormat = null;
|
||||
$scope.currentEntity = null;
|
||||
$scope.currentRobot = null;
|
||||
$scope.currentRobotHasPermission = null;
|
||||
|
||||
$scope.clearCounter++;
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ from endpoints.api.organization import (OrganizationList, OrganizationMember,
|
|||
OrganizationApplicationResetClientSecret)
|
||||
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository
|
||||
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
|
||||
RepositoryTeamPermissionList, RepositoryUserPermissionList)
|
||||
RepositoryTeamPermissionList, RepositoryUserPermissionList,
|
||||
RepositoryUserTransitivePermission)
|
||||
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
|
||||
SuperUserSendRecoveryEmail, ChangeLog,
|
||||
SuperUserOrganizationManagement, SuperUserOrganizationList)
|
||||
|
@ -728,6 +729,58 @@ class TestTeamMemberListBuynlargeOwners(ApiTestCase):
|
|||
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):
|
||||
def setUp(self):
|
||||
ApiTestCase.setUp(self)
|
||||
|
|
Reference in a new issue