From 9257b167664dad1d84130ae4fcbcc52bfa7575ac Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Thu, 13 Dec 2018 18:45:48 +0100 Subject: [PATCH 01/14] db: use asbool to detect if ping conenction or debug is set. Otherwise just those two flags present would trigger the conditions. --- rhodecode/lib/utils2.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py index 3d6eaf38..5322ea98 100644 --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -43,6 +43,7 @@ import sqlalchemy.exc import sqlalchemy.sql import webob import pyramid.threadlocal +from pyramid.settings import asbool import rhodecode from rhodecode.translation import _, _pluralize @@ -361,7 +362,8 @@ def ping_connection(connection, branch): def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): """Custom engine_from_config functions.""" log = logging.getLogger('sqlalchemy.engine') - _ping_connection = configuration.pop('sqlalchemy.db1.ping_connection', None) + use_ping_connection = asbool(configuration.pop('sqlalchemy.db1.ping_connection', None)) + debug = asbool(configuration.get('debug')) engine = sqlalchemy.engine_from_config(configuration, prefix, **kwargs) @@ -370,12 +372,12 @@ def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): normal = '\x1b[0m' return ''.join([color_seq, sql, normal]) - if configuration['debug'] or _ping_connection: + if use_ping_connection: + log.debug('Adding ping_connection on the engine config.') sqlalchemy.event.listen(engine, "engine_connect", ping_connection) - if configuration['debug']: + if debug: # attach events only for debug configuration - def before_cursor_execute(conn, cursor, statement, parameters, context, executemany): setattr(conn, 'query_start_time', time.time()) @@ -394,10 +396,8 @@ def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): parameters, context, executemany): delattr(conn, 'query_start_time') - sqlalchemy.event.listen(engine, "before_cursor_execute", - before_cursor_execute) - sqlalchemy.event.listen(engine, "after_cursor_execute", - after_cursor_execute) + sqlalchemy.event.listen(engine, "before_cursor_execute", before_cursor_execute) + sqlalchemy.event.listen(engine, "after_cursor_execute", after_cursor_execute) return engine From 1d027eb16add8ffcc2f8e277bf4ccb651020fa41 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Thu, 13 Dec 2018 22:02:46 +0100 Subject: [PATCH 02/14] pull-requests: validate ref types for pull request so users cannot provide wrongs ones. --- .../api/tests/test_create_pull_request.py | 19 ++++++++++++ rhodecode/api/tests/test_utils.py | 4 +-- rhodecode/api/utils.py | 30 ++++++++++++------- rhodecode/model/pull_request.py | 8 +++-- 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/rhodecode/api/tests/test_create_pull_request.py b/rhodecode/api/tests/test_create_pull_request.py index 0743e6e8..6ff6c017 100644 --- a/rhodecode/api/tests/test_create_pull_request.py +++ b/rhodecode/api/tests/test_create_pull_request.py @@ -55,6 +55,25 @@ class TestCreatePullRequestApi(object): expected = 'Missing non optional `{}` arg in JSON DATA'.format(key) assert_error(id_, expected, given=response.body) + @pytest.mark.backends("git", "hg") + @pytest.mark.parametrize('source_ref', [ + 'bookmarg:default:initial' + ]) + def test_create_with_wrong_refs_data(self, backend, source_ref): + + data = self._prepare_data(backend) + data['source_ref'] = source_ref + + id_, params = build_data( + self.apikey_regular, 'create_pull_request', **data) + + response = api_call(self.app, params) + + expected = "Ref `{}` type is not allowed. " \ + "Only:['bookmark', 'book', 'tag', 'branch'] " \ + "are possible.".format(source_ref) + assert_error(id_, expected, given=response.body) + @pytest.mark.backends("git", "hg") def test_create_with_correct_data(self, backend): data = self._prepare_data(backend) diff --git a/rhodecode/api/tests/test_utils.py b/rhodecode/api/tests/test_utils.py index a3b2084a..3f064a7e 100644 --- a/rhodecode/api/tests/test_utils.py +++ b/rhodecode/api/tests/test_utils.py @@ -84,11 +84,11 @@ class TestResolveRefOrError(object): def test_non_supported_refs(self): repo = Mock() - ref = 'ancestor:ref' + ref = 'bookmark:ref' with pytest.raises(JSONRPCError) as excinfo: utils.resolve_ref_or_error(ref, repo) expected_message = ( - 'The specified value:ancestor:`ref` does not exist, or is not allowed.') + 'The specified value:bookmark:`ref` does not exist, or is not allowed.') assert excinfo.value.message == expected_message def test_branch_is_not_found(self): diff --git a/rhodecode/api/utils.py b/rhodecode/api/utils.py index 7c972ea4..d1de34d5 100644 --- a/rhodecode/api/utils.py +++ b/rhodecode/api/utils.py @@ -388,7 +388,19 @@ def get_commit_or_error(ref, repo): raise JSONRPCError('Ref `{ref}` does not exist'.format(ref=ref)) -def resolve_ref_or_error(ref, repo): +def _get_ref_hash(repo, type_, name): + vcs_repo = repo.scm_instance() + if type_ in ['branch'] and vcs_repo.alias in ('hg', 'git'): + return vcs_repo.branches[name] + elif type_ in ['bookmark', 'book'] and vcs_repo.alias == 'hg': + return vcs_repo.bookmarks[name] + else: + raise ValueError() + + +def resolve_ref_or_error(ref, repo, allowed_ref_types=None): + allowed_ref_types = allowed_ref_types or ['bookmark', 'book', 'tag', 'branch'] + def _parse_ref(type_, name, hash_=None): return type_, name, hash_ @@ -399,6 +411,12 @@ def resolve_ref_or_error(ref, repo): 'Ref `{ref}` given in a wrong format. Please check the API' ' documentation for more details'.format(ref=ref)) + if ref_type not in allowed_ref_types: + raise JSONRPCError( + 'Ref `{ref}` type is not allowed. ' + 'Only:{allowed_refs} are possible.'.format( + ref=ref, allowed_refs=allowed_ref_types)) + try: ref_hash = ref_hash or _get_ref_hash(repo, ref_type, ref_name) except (KeyError, ValueError): @@ -429,13 +447,3 @@ def _get_commit_dict( "raw_diff": raw_diff, "stats": stats } - - -def _get_ref_hash(repo, type_, name): - vcs_repo = repo.scm_instance() - if type_ == 'branch' and vcs_repo.alias in ('hg', 'git'): - return vcs_repo.branches[name] - elif type_ == 'bookmark' and vcs_repo.alias == 'hg': - return vcs_repo.bookmarks[name] - else: - raise ValueError() diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py index d036e109..3941853d 100644 --- a/rhodecode/model/pull_request.py +++ b/rhodecode/model/pull_request.py @@ -129,6 +129,8 @@ class PullRequestModel(BaseModel): 'This pull request cannot be updated because the source ' 'reference is missing.'), } + REF_TYPES = ['bookmark', 'book', 'tag', 'branch'] + UPDATABLE_REF_TYPES = ['bookmark', 'book', 'branch'] def __get_pull_request(self, pull_request): return self._get_instance(( @@ -671,7 +673,7 @@ class PullRequestModel(BaseModel): def has_valid_update_type(self, pull_request): source_ref_type = pull_request.source_ref_parts.type - return source_ref_type in ['book', 'branch', 'tag'] + return source_ref_type in self.REF_TYPES def update_commits(self, pull_request): """ @@ -751,7 +753,7 @@ class PullRequestModel(BaseModel): pull_request_version = pull_request try: - if target_ref_type in ('tag', 'branch', 'book'): + if target_ref_type in self.REF_TYPES: target_commit = target_repo.get_commit(target_ref_name) else: target_commit = target_repo.get_commit(target_ref_id) @@ -1326,7 +1328,7 @@ class PullRequestModel(BaseModel): return merge_state def _refresh_reference(self, reference, vcs_repository): - if reference.type in ('branch', 'book'): + if reference.type in self.UPDATABLE_REF_TYPES: name_or_id = reference.name else: name_or_id = reference.commit_id From a95bd9622ce194293b4afba06719139c0b762bc9 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Thu, 20 Dec 2018 01:01:02 +0100 Subject: [PATCH 03/14] svn: support proxy-prefix properly fixes #5521 --- rhodecode/lib/middleware/simplesvn.py | 9 +++++---- rhodecode/tests/lib/middleware/test_simplesvn.py | 14 +++++++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/rhodecode/lib/middleware/simplesvn.py b/rhodecode/lib/middleware/simplesvn.py index 66233344..6d4ab29e 100644 --- a/rhodecode/lib/middleware/simplesvn.py +++ b/rhodecode/lib/middleware/simplesvn.py @@ -51,7 +51,8 @@ class SimpleSvnApp(object): data = environ['wsgi.input'] req_method = environ['REQUEST_METHOD'] has_content_length = 'CONTENT_LENGTH' in environ - path_info = self._get_url(environ['PATH_INFO']) + path_info = self._get_url( + self.config.get('subversion_http_server_url', ''), environ['PATH_INFO']) transfer_encoding = environ.get('HTTP_TRANSFER_ENCODING', '') log.debug('Handling: %s method via `%s`', req_method, path_info) @@ -117,9 +118,9 @@ class SimpleSvnApp(object): response_headers) return response.iter_content(chunk_size=1024) - def _get_url(self, path): - url_path = urlparse.urljoin( - self.config.get('subversion_http_server_url', ''), path) + def _get_url(self, svn_http_server, path): + svn_http_server_url = (svn_http_server or '').rstrip('/') + url_path = urlparse.urljoin(svn_http_server_url + '/', (path or '').lstrip('/')) url_path = urllib.quote(url_path, safe="/:=~+!$,;'") return url_path diff --git a/rhodecode/tests/lib/middleware/test_simplesvn.py b/rhodecode/tests/lib/middleware/test_simplesvn.py index 837013be..4a5d3190 100644 --- a/rhodecode/tests/lib/middleware/test_simplesvn.py +++ b/rhodecode/tests/lib/middleware/test_simplesvn.py @@ -161,9 +161,17 @@ class TestSimpleSvnApp(object): response_headers = self.app._get_response_headers(headers) assert sorted(response_headers) == sorted(expected_headers) - def test_get_url(self): - url = self.app._get_url(self.path) - expected_url = '{}{}'.format(self.host.strip('/'), self.path) + @pytest.mark.parametrize('svn_http_url, path_info, expected_url', [ + ('http://localhost:8200', '/repo_name', 'http://localhost:8200/repo_name'), + ('http://localhost:8200///', '/repo_name', 'http://localhost:8200/repo_name'), + ('http://localhost:8200', '/group/repo_name', 'http://localhost:8200/group/repo_name'), + ('http://localhost:8200/', '/group/repo_name', 'http://localhost:8200/group/repo_name'), + ('http://localhost:8200/prefix', '/repo_name', 'http://localhost:8200/prefix/repo_name'), + ('http://localhost:8200/prefix', 'repo_name', 'http://localhost:8200/prefix/repo_name'), + ('http://localhost:8200/prefix', '/group/repo_name', 'http://localhost:8200/prefix/group/repo_name') + ]) + def test_get_url(self, svn_http_url, path_info, expected_url): + url = self.app._get_url(svn_http_url, path_info) assert url == expected_url def test_call(self): From d632d6691b96d4356203f3d2aa02c956504214b4 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Sun, 23 Dec 2018 20:37:05 +0100 Subject: [PATCH 04/14] vcs: handle excessive slashes in from of the repo name path, fixes #5522 --- rhodecode/lib/middleware/simplehg.py | 9 ++++++--- rhodecode/lib/middleware/simplevcs.py | 10 +++------- rhodecode/tests/vcs_operations/test_vcs_operations.py | 10 ++++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/rhodecode/lib/middleware/simplehg.py b/rhodecode/lib/middleware/simplehg.py index 53ccb21b..60d78bcd 100644 --- a/rhodecode/lib/middleware/simplehg.py +++ b/rhodecode/lib/middleware/simplehg.py @@ -44,7 +44,11 @@ class SimpleHg(simplevcs.SimpleVCS): :param environ: environ where PATH_INFO is stored """ - return environ['PATH_INFO'].strip('/') + repo_name = environ['PATH_INFO'] + if repo_name and repo_name.startswith('/'): + # remove only the first leading / + repo_name = repo_name[1:] + return repo_name.rstrip('/') _ACTION_MAPPING = { 'changegroup': 'pull', @@ -147,8 +151,7 @@ class SimpleHg(simplevcs.SimpleVCS): return default def _create_wsgi_app(self, repo_path, repo_name, config): - return self.scm_app.create_hg_wsgi_app( - repo_path, repo_name, config) + return self.scm_app.create_hg_wsgi_app(repo_path, repo_name, config) def _create_config(self, extras, repo_name): config = utils.make_db_config(repo=repo_name) diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py index 3c47d0ae..2e034b01 100644 --- a/rhodecode/lib/middleware/simplevcs.py +++ b/rhodecode/lib/middleware/simplevcs.py @@ -153,12 +153,10 @@ class SimpleVCS(object): @property def base_path(self): - settings_path = self.repo_vcs_config.get( - *VcsSettingsModel.PATH_SETTING) + settings_path = self.repo_vcs_config.get(*VcsSettingsModel.PATH_SETTING) if not settings_path: - settings_path = self.global_vcs_config.get( - *VcsSettingsModel.PATH_SETTING) + settings_path = self.global_vcs_config.get(*VcsSettingsModel.PATH_SETTING) if not settings_path: # try, maybe we passed in explicitly as config option @@ -396,7 +394,6 @@ class SimpleVCS(object): meta.Session.remove() def _handle_request(self, environ, start_response): - if not self._check_ssl(environ, start_response): reason = ('SSL required, while RhodeCode was unable ' 'to detect this as SSL request') @@ -514,8 +511,7 @@ class SimpleVCS(object): plugin_cache_active, cache_ttl = auth_result.get( 'auth_data', {}).get('_ttl_cache') or (False, 0) else: - return auth_result.wsgi_application( - environ, start_response) + return auth_result.wsgi_application(environ, start_response) # ============================================================== # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME diff --git a/rhodecode/tests/vcs_operations/test_vcs_operations.py b/rhodecode/tests/vcs_operations/test_vcs_operations.py index 1365f5fd..86d7aab1 100644 --- a/rhodecode/tests/vcs_operations/test_vcs_operations.py +++ b/rhodecode/tests/vcs_operations/test_vcs_operations.py @@ -141,6 +141,16 @@ class TestVCSOperations(object): stdout, stderr = Command('/tmp').execute('git clone', clone_url) assert 'not found' in stderr + def test_clone_hg_with_slashes(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) + assert 'HTTP Error 404: Not Found' in stderr + + def test_clone_git_with_slashes(self, rc_web_server, tmpdir): + clone_url = rc_web_server.repo_clone_url('//' + GIT_REPO) + stdout, stderr = Command('/tmp').execute('git clone', clone_url) + assert 'not found' in stderr + def test_clone_existing_path_hg_not_in_database( self, rc_web_server, tmpdir, fs_repo_only): From 596657fd2c0173d03be1741e69f82bce8f9f9a83 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Thu, 27 Dec 2018 17:38:19 +0100 Subject: [PATCH 05/14] security: fixed xss in context diff menu. --- rhodecode/templates/codeblocks/diffs.mako | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rhodecode/templates/codeblocks/diffs.mako b/rhodecode/templates/codeblocks/diffs.mako index fcc5bd61..f705090e 100644 --- a/rhodecode/templates/codeblocks/diffs.mako +++ b/rhodecode/templates/codeblocks/diffs.mako @@ -909,6 +909,8 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number): }; var animateText = $.debounce(100, function(fPath, anchorId) { + fPath = Select2.util.escapeMarkup(fPath); + // animate setting the text var callback = function () { $('.fpath-placeholder-text').animate({'opacity': 1.00}, 200) From 2fb928833808136b9e14e19e805b656b6fa029af Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Fri, 28 Dec 2018 15:10:58 +0100 Subject: [PATCH 06/14] routes: updated routes to include EE entries. --- rhodecode/public/js/rhodecode/routes.js | 43 ++++++++++++++++++------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js index af41a39a..f9bdbbd3 100644 --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -80,14 +80,12 @@ function registerRCRoutes() { pyroutes.register('admin_settings_search', '/_admin/settings/search', []); pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []); pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []); - pyroutes.register('admin_settings_automation', '/_admin/_admin/settings/automation', []); pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []); pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []); pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []); pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []); pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []); pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []); - pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []); pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []); pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []); pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []); @@ -106,8 +104,6 @@ function registerRCRoutes() { pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']); pyroutes.register('user_force_password_reset', '/_admin/users/%(user_id)s/password_reset', ['user_id']); pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']); - pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']); - pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']); pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']); pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']); pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']); @@ -139,9 +135,7 @@ function registerRCRoutes() { pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []); pyroutes.register('channelstream_proxy', '/_channelstream', []); - pyroutes.register('login', '/_admin/login', []); pyroutes.register('logout', '/_admin/logout', []); - pyroutes.register('register', '/_admin/register', []); pyroutes.register('reset_password', '/_admin/password_reset', []); pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []); pyroutes.register('home', '/', []); @@ -236,8 +230,6 @@ function registerRCRoutes() { pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']); pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); - pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']); - pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']); pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); @@ -246,7 +238,6 @@ function registerRCRoutes() { pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']); pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']); pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']); - pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']); pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']); pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']); pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']); @@ -258,7 +249,6 @@ function registerRCRoutes() { pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']); pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']); - pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']); pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']); pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); @@ -295,8 +285,6 @@ function registerRCRoutes() { pyroutes.register('my_account_update', '/_admin/my_account/update', []); pyroutes.register('my_account_password', '/_admin/my_account/password', []); pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []); - pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []); - pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []); pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []); pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []); pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []); @@ -333,4 +321,35 @@ function registerRCRoutes() { pyroutes.register('debug_style_home', '/_admin/debug_style', []); pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']); pyroutes.register('apiv2', '/_admin/api', []); + pyroutes.register('admin_settings_license', '/_admin/settings/license', []); + pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []); + pyroutes.register('login', '/_admin/login', []); + pyroutes.register('register', '/_admin/register', []); + pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']); + pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']); + pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']); + pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']); + pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']); + pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']); + pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []); + pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []); + pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []); + pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []); + pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']); + pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']); + pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']); + pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']); + pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []); + pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']); + pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []); + pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []); + pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []); + pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []); + pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []); + pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []); + pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']); + pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']); + pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']); + pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']); + pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']); } From de789db4d62c29bcd7b29c29370e44e41d8e66e3 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Sat, 22 Dec 2018 10:24:14 +0100 Subject: [PATCH 07/14] docs: updated configuration for nginx and reverse proxy. --- docs/admin/nginx-config-example.rst | 65 ++++++++++++++++++----------- docs/admin/nginx-proxy-conf.rst | 27 ++++++++---- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/docs/admin/nginx-config-example.rst b/docs/admin/nginx-config-example.rst index 02c76350..8dff1c70 100644 --- a/docs/admin/nginx-config-example.rst +++ b/docs/admin/nginx-config-example.rst @@ -6,16 +6,16 @@ Use the following example to configure Nginx as a your web server. .. code-block:: nginx - ## rate limiter for certain pages to prevent brute force attacks + ## Rate limiter for certain pages to prevent brute force attacks limit_req_zone $binary_remote_addr zone=req_limit:10m rate=1r/s; - ## custom log format + ## Custom log format log_format log_custom '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time $pipe'; - ## define upstream (local RhodeCode instance) to connect to + ## Define one or more upstreams (local RhodeCode instance) to connect to upstream rc { # Url to running RhodeCode instance. # This is shown as `- URL: ` in output from rccontrol status. @@ -53,10 +53,10 @@ Use the following example to configure Nginx as a your web server. ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; - # strict http prevents from https -> http downgrade + ## Strict http prevents from https -> http downgrade add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; - # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits + ## Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits #ssl_dhparam /etc/nginx/ssl/dhparam.pem; rewrite ^/(.+)$ https://rhodecode.myserver.com/_admin/gists/$1; @@ -66,27 +66,37 @@ Use the following example to configure Nginx as a your web server. ## MAIN SSL enabled server server { - listen 443 ssl; + listen 443 ssl http2; server_name rhodecode.myserver.com; access_log /var/log/nginx/rhodecode.access.log log_custom; error_log /var/log/nginx/rhodecode.error.log; - ssl on; ssl_certificate rhodecode.myserver.com.crt; ssl_certificate_key rhodecode.myserver.com.key; + # enable session resumption to improve https performance + # http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html + ssl_session_cache shared:SSL:50m; ssl_session_timeout 5m; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; - - # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits + ## Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits #ssl_dhparam /etc/nginx/ssl/dhparam.pem; - # example of proxy.conf can be found in our docs. - include /etc/nginx/proxy.conf; + # enables server-side protection from BEAST attacks + # http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html + ssl_prefer_server_ciphers on; + + # disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0 + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + + # ciphers chosen for forward secrecy and compatibility + # http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html + ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; + + client_body_buffer_size 128k; + # maximum number and size of buffers for large headers to read from client request + large_client_header_buffers 16 256k; ## uncomment to serve static files by Nginx, recommended for performance # location /_static/rhodecode { @@ -101,43 +111,48 @@ Use the following example to configure Nginx as a your web server. # alias /path/to/.rccontrol/enterprise-1/static; # } - ## channelstream websocket handling + ## channelstream location handler, if channelstream live chat and notifications + ## are enable this will proxy the requests to channelstream websocket server location /_channelstream { rewrite /_channelstream/(.*) /$1 break; - - proxy_pass http://127.0.0.1:9800; + gzip off; + tcp_nodelay off; proxy_connect_timeout 10; proxy_send_timeout 10m; proxy_read_timeout 10m; - tcp_nodelay off; + proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - gzip off; + proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; + + proxy_pass http://127.0.0.1:9800; } ## rate limit this endpoint to prevent login page brute-force attacks location /_admin/login { limit_req zone=req_limit burst=10 nodelay; - try_files $uri @rhode; + try_files $uri @rhodecode_http; } location / { - try_files $uri @rhode; + try_files $uri @rhodecode_http; } - location @rhode { - proxy_pass http://rc; + location @rhodecode_http { + # example of proxy.conf can be found in our docs. + include /etc/nginx/proxy.conf; + proxy_pass http://rc; } - ## custom 502 error page. Will be displayed while RhodeCode server - ## is turned off + ## Custom 502 error page. + ## Will be displayed while RhodeCode server is turned off error_page 502 /502.html; location = /502.html { #root /path/to/.rccontrol/community-1/static; diff --git a/docs/admin/nginx-proxy-conf.rst b/docs/admin/nginx-proxy-conf.rst index e468c027..1445be0b 100644 --- a/docs/admin/nginx-proxy-conf.rst +++ b/docs/admin/nginx-proxy-conf.rst @@ -12,23 +12,36 @@ timeout during large pushes. proxy_redirect off; proxy_set_header Host $http_host; + ## If you use HTTPS make sure you disable gzip compression + ## to be safe against BREACH attack. + gzip off; + + # Don't buffer requests in NGINX stream them using chunked-encoding + proxy_buffering off; + + ## This is also required for later GIT to use streaming. + ## Works only for Nginx 1.7.11 and newer + proxy_request_buffering off; + proxy_http_version 1.1; + + ## Set this to a larger number if you experience timeouts + ## or 413 Request Entity Too Large, 10GB is enough for most cases + client_max_body_size 10240m; + ## needed for container auth - # proxy_set_header REMOTE_USER $remote_user; - # proxy_set_header X-Forwarded-User $remote_user; + # proxy_set_header REMOTE_USER $remote_user; + # proxy_set_header X-Forwarded-User $remote_user; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Proxy-host $proxy_host; - proxy_buffering off; + proxy_connect_timeout 7200; proxy_send_timeout 7200; proxy_read_timeout 7200; proxy_buffers 8 32k; - # Set this to a larger number if you experience timeouts - client_max_body_size 1024m; - client_body_buffer_size 128k; - large_client_header_buffers 8 64k; + add_header X-Frame-Options SAMEORIGIN; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; From 966eb88577a4659a010f648938957ed536d60119 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Mon, 31 Dec 2018 17:00:57 +0100 Subject: [PATCH 08/14] downlaods: properly encode " in the filenames, and add RFC 5987 header for non-ascii files. --- .../apps/repository/tests/test_repo_files.py | 2 +- rhodecode/apps/repository/views/repo_files.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/rhodecode/apps/repository/tests/test_repo_files.py b/rhodecode/apps/repository/tests/test_repo_files.py index 61d07668..3a4dca68 100644 --- a/rhodecode/apps/repository/tests/test_repo_files.py +++ b/rhodecode/apps/repository/tests/test_repo_files.py @@ -428,7 +428,7 @@ class TestRawFileHandling(object): repo_name=backend.repo_name, commit_id=commit.raw_id, f_path='vcs/nodes.py'),) - assert response.content_disposition == "attachment; filename=nodes.py" + assert response.content_disposition == 'attachment; filename="nodes.py"; filename*=UTF-8\'\'nodes.py' assert response.content_type == "text/x-python" def test_download_file_wrong_cs(self, backend): diff --git a/rhodecode/apps/repository/views/repo_files.py b/rhodecode/apps/repository/views/repo_files.py index 0cb07931..ed49ce90 100644 --- a/rhodecode/apps/repository/views/repo_files.py +++ b/rhodecode/apps/repository/views/repo_files.py @@ -24,6 +24,7 @@ import os import shutil import tempfile import collections +import urllib from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound from pyramid.view import view_config @@ -708,9 +709,14 @@ class RepoFilesView(RepoAppView): return Response(html) - def _get_attachement_disposition(self, f_path): - return 'attachment; filename=%s' % \ - safe_str(f_path.split(Repository.NAME_SEP)[-1]) + def _get_attachement_headers(self, f_path): + f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1]) + safe_path = f_name.replace('"', '\\"') + encoded_path = urllib.quote(f_name) + + return "attachment; " \ + "filename=\"{}\"; " \ + "filename*=UTF-8\'\'{}".format(safe_path, encoded_path) @LoginRequired() @HasRepoPermissionAnyDecorator( @@ -765,7 +771,7 @@ class RepoFilesView(RepoAppView): mimetype, disposition = 'text/plain', 'inline' if disposition == 'attachment': - disposition = self._get_attachement_disposition(f_path) + disposition = self._get_attachement_headers(f_path) def stream_node(): yield file_node.raw_bytes @@ -804,7 +810,7 @@ class RepoFilesView(RepoAppView): # overwrite our pointer with the REAL large-file file_node = lf_node - disposition = self._get_attachement_disposition(f_path) + disposition = self._get_attachement_headers(f_path) def stream_node(): yield file_node.raw_bytes From cd0d654a5f7ce75ad4244624baf572ab38b32b98 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Sat, 22 Dec 2018 10:16:17 +0100 Subject: [PATCH 09/14] vcs: streaming will use now 100kb chunks readers for faster throughput --- rhodecode/lib/middleware/utils/scm_app_http.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/rhodecode/lib/middleware/utils/scm_app_http.py b/rhodecode/lib/middleware/utils/scm_app_http.py index bbf3c444..6a1d275e 100644 --- a/rhodecode/lib/middleware/utils/scm_app_http.py +++ b/rhodecode/lib/middleware/utils/scm_app_http.py @@ -133,6 +133,18 @@ class VcsHttpProxy(object): return _maybe_stream_response(response) +def read_in_chunks(stream_obj, block_size=1024, chunks=-1): + """ + Read Stream in chunks, default chunk size: 1k. + """ + while chunks: + data = stream_obj.read(block_size) + if not data: + break + yield data + chunks -= 1 + + def _is_request_chunked(environ): stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked' return stream @@ -144,7 +156,8 @@ def _maybe_stream_request(environ): log.debug('handling request `%s` with stream support: %s', path, stream) if stream: - return environ['wsgi.input'] + # set stream by 256k + return read_in_chunks(environ['wsgi.input'], block_size=1024 * 256) else: return environ['wsgi.input'].read() @@ -156,7 +169,8 @@ def _maybe_stream_response(response): stream = _is_chunked(response) log.debug('returning response with stream: %s', stream) if stream: - return response.raw.read_chunked() + # read in 256k Chunks + return response.raw.read_chunked(amt=1024 * 256) else: return [response.content] From 7cc67d77fd883ab1237f5559e8b7a6866833630f Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Mon, 31 Dec 2018 17:13:25 +0100 Subject: [PATCH 10/14] docs: added release notes for 4.15.1 --- docs/release-notes/release-notes-4.15.1.rst | 50 +++++++++++++++++++++ docs/release-notes/release-notes.rst | 1 + 2 files changed, 51 insertions(+) create mode 100644 docs/release-notes/release-notes-4.15.1.rst diff --git a/docs/release-notes/release-notes-4.15.1.rst b/docs/release-notes/release-notes-4.15.1.rst new file mode 100644 index 00000000..13169052 --- /dev/null +++ b/docs/release-notes/release-notes-4.15.1.rst @@ -0,0 +1,50 @@ +|RCE| 4.15.1 |RNS| +------------------ + +Release Date +^^^^^^^^^^^^ + +- 2019-01-01 + + +New Features +^^^^^^^^^^^^ + + + +General +^^^^^^^ + +- Downloads: properly encode " in the filenames, and add RFC 5987 header for non-ascii files. +- Documentation: updated configuration for Nginx and reverse proxy. +- VCS: streaming will use now 100kb chunks for faster network throughput. + + +Security +^^^^^^^^ + +- Diffs: fixed xss in context diff menu. +- Downloads: properly encode " in the filenames, prevents from hiding executable + files disguised in another type of file using crafted file names. + +Performance +^^^^^^^^^^^ + + + +Fixes +^^^^^ + +- VCS: handle excessive slashes in from of the repo name path, fixes #5522. + This prevents 500 errors when excessive slashes are used +- SVN: support proxy-prefix properly, fixes #5521. +- Pull requests: validate ref types on API calls for pull request so users cannot + provide wrongs ones. +- Scheduler: fix url generation with proxy prefix. +- Celery: add DB connection ping to validate DB connection is working at worker startup. + + +Upgrade notes +^^^^^^^^^^^^^ + +- Scheduled release addressing reported problems in 4.15.X releases. diff --git a/docs/release-notes/release-notes.rst b/docs/release-notes/release-notes.rst index 384ad3ef..9d7dd371 100644 --- a/docs/release-notes/release-notes.rst +++ b/docs/release-notes/release-notes.rst @@ -9,6 +9,7 @@ Release Notes .. toctree:: :maxdepth: 1 + release-notes-4.15.1.rst release-notes-4.15.0.rst release-notes-4.14.1.rst release-notes-4.14.0.rst From 0e0242ec78003f45b0caa4d76b657fd01c537f53 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Wed, 2 Jan 2019 11:13:25 +0100 Subject: [PATCH 11/14] release: Start preparation for 4.15.1 --- .bumpversion.cfg | 2 +- .release.cfg | 14 ++++---------- rhodecode/VERSION | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 24f10812..ccb73914 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.15.0 +current_version = 4.15.1 message = release: Bump version {current_version} to {new_version} [bumpversion:file:rhodecode/VERSION] diff --git a/.release.cfg b/.release.cfg index 61a5b6c0..b25c2f5b 100644 --- a/.release.cfg +++ b/.release.cfg @@ -5,26 +5,20 @@ done = false done = true [task:rc_tools_pinned] -done = true [task:fixes_on_stable] -done = true [task:pip2nix_generated] -done = true [task:changelog_updated] -done = true [task:generate_api_docs] -done = true - -[task:updated_translation] -done = true [release] -state = prepared -version = 4.15.0 +state = in_progress +version = 4.15.1 + +[task:updated_translation] [task:generate_js_routes] diff --git a/rhodecode/VERSION b/rhodecode/VERSION index f029ee57..68289521 100644 --- a/rhodecode/VERSION +++ b/rhodecode/VERSION @@ -1 +1 @@ -4.15.0 \ No newline at end of file +4.15.1 \ No newline at end of file From 30493cb89b5e3853449f9bdcd63d13c5f97e4a08 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Wed, 2 Jan 2019 11:23:21 +0100 Subject: [PATCH 12/14] release: updated pip2nix output for 4.15.1 --- .release.cfg | 4 ++++ pkgs/python-packages.nix | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.release.cfg b/.release.cfg index b25c2f5b..0fb87b86 100644 --- a/.release.cfg +++ b/.release.cfg @@ -5,14 +5,18 @@ done = false done = true [task:rc_tools_pinned] +done = true [task:fixes_on_stable] +done = true [task:pip2nix_generated] [task:changelog_updated] +done = true [task:generate_api_docs] +done = true [release] state = in_progress diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix index 17a4e291..e88778b5 100644 --- a/pkgs/python-packages.nix +++ b/pkgs/python-packages.nix @@ -1657,7 +1657,7 @@ self: super: { }; }; "rhodecode-enterprise-ce" = super.buildPythonPackage { - name = "rhodecode-enterprise-ce-4.15.0"; + name = "rhodecode-enterprise-ce-4.15.1"; buildInputs = [ self."pytest" self."py" From 622279f95ced00a0da16ba605c79340a7dc929b4 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Wed, 2 Jan 2019 11:23:23 +0100 Subject: [PATCH 13/14] release: Finish preparation for 4.15.1 --- .release.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.release.cfg b/.release.cfg index 0fb87b86..d48c44d4 100644 --- a/.release.cfg +++ b/.release.cfg @@ -11,6 +11,7 @@ done = true done = true [task:pip2nix_generated] +done = true [task:changelog_updated] done = true @@ -19,7 +20,7 @@ done = true done = true [release] -state = in_progress +state = prepared version = 4.15.1 [task:updated_translation] From 9dd589e264a82bfe9761b82d0ac053203a207476 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Wed, 2 Jan 2019 11:23:25 +0100 Subject: [PATCH 14/14] Added tag v4.15.1 for changeset 14502561d22e