def toggle_locking(self, repo_name): """ Toggle locking of repository by simple GET call to url :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if repo.enable_locking: if repo.locked[0]: Repository.unlock(repo) action = _('Unlocked') else: Repository.lock(repo, c.rhodecode_user.user_id, lock_reason=Repository.LOCK_WEB) action = _('Locked') h.flash(_('Repository has been %s') % action, category='success') except Exception: log.exception("Exception during unlocking") h.flash(_('An error occurred during unlocking'), category='error') return redirect(url('summary_home', repo_name=repo_name))
def test_api_lock_repo_lock_optional_locked(self, backend): # TODO: Provide a fixture locked_repository or similar repo = Repository.get_by_repo_name(backend.repo_name) user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) Repository.lock(repo, user.user_id, lock_reason=Repository.LOCK_API) id_, params = build_data(self.apikey, 'lock', repoid=backend.repo_name) response = api_call(self.app, params) time_ = response.json['result']['locked_since'] expected = { 'repo': backend.repo_name, 'locked': True, 'locked_since': time_, 'locked_by': TEST_USER_ADMIN_LOGIN, 'lock_state_changed': False, 'lock_reason': Repository.LOCK_API, 'msg': ('Repo `%s` locked by `%s` on `%s`.' % (backend.repo_name, TEST_USER_ADMIN_LOGIN, json.dumps(time_to_datetime(time_)))) } assert_ok(id_, expected, given=response.body)
def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir): clone_url = rc_web_server.repo_clone_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url, tmpdir.strpath) # lock repo r = Repository.get_by_repo_name(HG_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # push fails repo is locked by other user ! push_url = rc_web_server.repo_clone_url(HG_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) stdout, stderr = _add_files_and_push('hg', tmpdir.strpath, clone_url=push_url) msg = ( """abort: HTTP Error 400: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def post_pull(extras): """Hook executed after client pulls the code.""" user = User.get_by_username(extras.username) action = 'pull' action_logger(user, action, extras.repository, extras.ip, commit=True) # extension hook call post_pull_extension(**extras) output = '' # make lock is a tri state False, True, None. We only make lock on True if extras.make_lock is True: Repository.lock(Repository.get_by_repo_name(extras.repository), user.user_id, lock_reason=Repository.LOCK_PULL) msg = 'Made lock on repo `%s`' % (extras.repository, ) output += msg if extras.locked_by[0]: locked_by = User.get(extras.locked_by[0]).username reason = extras.locked_by[2] _http_ret = HTTPLockedRC( _locked_by_explanation(extras.repository, locked_by, reason)) if str(_http_ret.code).startswith('2'): # 2xx Codes don't raise exceptions output += _http_ret.title return HookResponse(0, output)
def test_push_on_locked_repo_by_other_user_git( self, rc_web_server, tmpdir): clone_url = rc_web_server.repo_clone_url(GIT_REPO) stdout, stderr = Command('/tmp').execute( 'git clone', clone_url, tmpdir.strpath) # lock repo r = Repository.get_by_repo_name(GIT_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # push fails repo is locked by other user! push_url = rc_web_server.repo_clone_url( GIT_REPO, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) stdout, stderr = _add_files_and_push( 'git', tmpdir.strpath, clone_url=push_url) err = 'Repository `%s` locked by user `%s`' % ( GIT_REPO, TEST_USER_ADMIN_LOGIN) # err = 'RPC failed; result=22, HTTP code = 423' assert err in stderr
def log_pull_action(ui, repo, **kwargs): """ Logs user last pull action :param ui: :param repo: """ ex = _extract_extras() user = User.get_by_username(ex.username) action = 'pull' action_logger(user, action, ex.repository, ex.ip, commit=True) # extension hook call from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PULL_HOOK', None) if isfunction(callback): kw = {} kw.update(ex) callback(**kw) if ex.make_lock is not None and ex.make_lock: Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id) #msg = 'Made lock on repo `%s`' % repository #sys.stdout.write(msg) if ex.locked_by[0]: locked_by = User.get(ex.locked_by[0]).username _http_ret = HTTPLockedRC(ex.repository, locked_by) if str(_http_ret.code).startswith('2'): #2xx Codes don't raise exceptions sys.stdout.write(_http_ret.title) return 0
def lock(self, apiuser, repoid, userid, locked): """ Set locking state on particular repository by given user :param apiuser: :param repoid: :param userid: :param locked: """ repo = get_repo_or_error(repoid) user = get_user_or_error(userid) locked = bool(locked) try: if locked: Repository.lock(repo, user.user_id) else: Repository.unlock(repo) return ('User `%s` set lock state for repo `%s` to `%s`' % (user.username, repo.repo_name, locked)) except Exception: log.error(traceback.format_exc()) raise JSONRPCError( 'Error occurred locking repository `%s`' % repo.repo_name )
def test_clone_after_repo_was_locked_git(self): #lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) msg = ("""The requested URL returned error: 423""") assert msg in stderr
def test_clone_after_repo_was_locked_hg(self): #lock repo r = Repository.get_by_repo_name(HG_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def test_api_get_user_locks_with_one_locked_repo_for_specific_user( self, backend): repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) Repository.lock(repo, User.get_by_username( self.TEST_USER_LOGIN).user_id) id_, params = build_data( self.apikey, 'get_user_locks', userid=self.TEST_USER_LOGIN) response = api_call(self.app, params) expected = [repo.get_api_data(include_secrets=True)] assert_ok(id_, expected, given=response.body)
def test_clone_after_repo_was_locked_hg(self): #lock repo r = Repository.get_by_repo_name(HG_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(HG_REPO) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) msg = ( """abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def test_clone_after_repo_was_locked_git(self): #lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #pull fails since repo is locked clone_url = _construct_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url) msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (GIT_REPO, TEST_USER_ADMIN_LOGIN)) #TODO: fix this somehow later on GIT, GIT is stupid and even if we throw # back 423 to it, it makes ANOTHER request and we fail there with 405 :/ msg = "405 Method Not Allowed" assert msg in stderr
def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir): # lock repo r = Repository.get_by_repo_name(GIT_REPO) Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) # pull fails since repo is locked clone_url = rc_web_server.repo_clone_url(GIT_REPO) stdout, stderr = Command('/tmp').execute('git clone', clone_url, tmpdir.strpath) lock_msg = ( 'remote: ERROR: Repository `vcs_test_git` locked by user ' + '`test_admin`. Reason:`lock_auto`') assert lock_msg in stderr assert 'remote: Pre pull hook failed: aborting' in stderr assert 'fatal: remote did not send all necessary objects' in stderr
def repo_locking(self, repo_name): """ Unlock repository when it is locked ! :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if request.POST.get('set_lock'): Repository.lock(repo, c.rhodecode_user.user_id) elif request.POST.get('set_unlock'): Repository.unlock(repo) except Exception, e: log.error(traceback.format_exc()) h.flash(_('An error occurred during unlocking'), category='error')
def test_api_get_user_locks_with_one_locked_repo( self, apikey_attr, expect_secrets, backend): repo = backend.create_repo(cur_user=self.TEST_USER_LOGIN) Repository.lock( repo, User.get_by_username(self.TEST_USER_LOGIN).user_id) apikey = getattr(self, apikey_attr) id_, params = build_data(apikey, 'get_user_locks') if apikey_attr == 'apikey': # super-admin should call in specific user id_, params = build_data(apikey, 'get_user_locks', userid=self.TEST_USER_LOGIN) response = api_call(self.app, params) expected = [repo.get_api_data(include_secrets=expect_secrets)] assert_ok(id_, expected, given=response.body)
def log_pull_action(ui, repo, **kwargs): """ Logs user last pull action :param ui: :param repo: """ try: rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}")) except: rc_extras = {} extras = dict(repo.ui.configitems('rhodecode_extras')) if 'username' in extras: username = extras['username'] repository = extras['repository'] scm = extras['scm'] make_lock = extras['make_lock'] ip = extras['ip'] elif 'username' in rc_extras: username = rc_extras['username'] repository = rc_extras['repository'] scm = rc_extras['scm'] make_lock = rc_extras['make_lock'] ip = rc_extras['ip'] else: raise Exception('Missing data in repo.ui and os.environ') user = User.get_by_username(username) action = 'pull' action_logger(user, action, repository, ip, commit=True) # extension hook call from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PULL_HOOK', None) if isfunction(callback): kw = {} kw.update(extras) callback(**kw) if make_lock is True: Repository.lock(Repository.get_by_repo_name(repository), user.user_id) #msg = 'Made lock on repo `%s`' % repository #sys.stdout.write(msg) return 0
def edit_advanced_locking(self, repo_name): """ Unlock repository when it is locked ! :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if request.POST.get('set_lock'): Repository.lock(repo, c.rhodecode_user.user_id, lock_reason=Repository.LOCK_WEB) h.flash(_('Locked repository'), category='success') elif request.POST.get('set_unlock'): Repository.unlock(repo) h.flash(_('Unlocked repository'), category='success') except Exception as e: log.exception("Exception during unlocking") h.flash(_('An error occurred during unlocking'), category='error') return redirect(url('edit_repo_advanced', repo_name=repo_name))
def test_push_on_locked_repo_by_other_user_hg(self): #clone some temp DEST = _get_tmp_dir() clone_url = _construct_url(HG_REPO, dest=DEST) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) #lock repo r = Repository.get_by_repo_name(HG_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #push fails repo is locked by other user ! stdout, stderr = _add_files_and_push('hg', DEST, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def toggle_locking(self, repo_name): """ Toggle locking of repository by simple GET call to url :param repo_name: """ try: repo = Repository.get_by_repo_name(repo_name) if repo.enable_locking: if repo.locked[0]: Repository.unlock(repo) action = _('Unlocked') else: Repository.lock(repo, c.rhodecode_user.user_id) action = _('Locked') h.flash(_('Repository has been %s') % action, category='success') except Exception, e: log.error(traceback.format_exc()) h.flash(_('An error occurred during unlocking'), category='error')
def test_push_on_locked_repo_by_other_user_hg(self): #clone some temp DEST = _get_tmp_dir() clone_url = _construct_url(HG_REPO, dest=DEST) stdout, stderr = Command('/tmp').execute('hg clone', clone_url) #lock repo r = Repository.get_by_repo_name(HG_REPO) # let this user actually push ! RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, perm='repository.write') Session().commit() Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) #push fails repo is locked by other user ! stdout, stderr = _add_files_and_push('hg', DEST, user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS) msg = ( """abort: HTTP Error 423: Repository `%s` locked by user `%s`""" % (HG_REPO, TEST_USER_ADMIN_LOGIN)) assert msg in stderr
def lock(self, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr('apiuser'))): """ Set locking state on particular repository by given user, if this command is runned by non-admin account userid is set to user who is calling this method :param apiuser: :param repoid: :param userid: :param locked: """ repo = get_repo_or_error(repoid) if HasPermissionAnyApi('hg.admin')(user=apiuser): pass elif HasRepoPermissionAnyApi('repository.admin', 'repository.write')(user=apiuser, repo_name=repo.repo_name): #make sure normal user does not pass someone else userid, #he is not allowed to do that if not isinstance(userid, Optional) and userid != apiuser.user_id: raise JSONRPCError( 'userid is not the same as your user' ) else: raise JSONRPCError('repository `%s` does not exist' % (repoid)) if isinstance(userid, Optional): userid = apiuser.user_id user = get_user_or_error(userid) if isinstance(locked, Optional): lockobj = Repository.getlock(repo) if lockobj[0] is None: return ('Repo `%s` not locked. Locked=`False`.' % (repo.repo_name)) else: userid, time_ = lockobj user = get_user_or_error(userid) return ('Repo `%s` locked by `%s`. Locked=`True`. ' 'Locked since: `%s`' % (repo.repo_name, user.username, json.dumps(time_to_datetime(time_)))) else: locked = str2bool(locked) try: if locked: Repository.lock(repo, user.user_id) else: Repository.unlock(repo) return ('User `%s` set lock state for repo `%s` to `%s`' % (user.username, repo.repo_name, locked)) except Exception: log.error(traceback.format_exc()) raise JSONRPCError( 'Error occurred locking repository `%s`' % repo.repo_name )