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):
|
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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Reference in a new issue