diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py index d6218de..ce067a8 100644 --- a/pagure/api/__init__.py +++ b/pagure/api/__init__.py @@ -122,6 +122,7 @@ class APIERROR(enum.Enum): ETRACKERREADONLY = "The issue tracker of this project is read-only" ENOPRSTATS = "No statistics could be computed for this PR" EUBLOCKED = "You have been blocked from this project" + EREBASENOTALLOWED = "You are not authorized to rebase this pull-request" def get_authorized_api_project(session, repo, user=None, namespace=None): diff --git a/pagure/api/fork.py b/pagure/api/fork.py index 0f0ba2d..fb2a4a7 100644 --- a/pagure/api/fork.py +++ b/pagure/api/fork.py @@ -665,11 +665,16 @@ def api_pull_request_rebase(repo, requestid, username=None, namespace=None): repo = _get_repo(repo, username, namespace) _check_pull_request(repo) _check_token(repo) - _get_request(repo, requestid) + request = _get_request(repo, requestid) if not is_repo_committer(repo): raise pagure.exceptions.APIError(403, error_code=APIERROR.ENOPRCLOSE) + if not request.allow_rebase: + raise pagure.exceptions.APIError( + 403, error_code=APIERROR.EREBASENOTALLOWED + ) + task = pagure.lib.tasks.rebase_pull_request.delay( repo.name, namespace, diff --git a/tests/test_pagure_flask_api.py b/tests/test_pagure_flask_api.py index 2cb96c0..e311da8 100644 --- a/tests/test_pagure_flask_api.py +++ b/tests/test_pagure_flask_api.py @@ -241,7 +241,7 @@ class PagureFlaskApitests(tests.SimplePagureTest): output = self.app.get("/api/0/-/error_codes") self.assertEqual(output.status_code, 200) data = json.loads(output.get_data(as_text=True)) - self.assertEqual(len(data), 36) + self.assertEqual(len(data), 37) self.assertEqual( sorted(data.keys()), sorted( @@ -282,6 +282,7 @@ class PagureFlaskApitests(tests.SimplePagureTest): "ETRACKERDISABLED", "ETRACKERREADONLY", "EUBLOCKED", + "EREBASENOTALLOWED", ] ), ) diff --git a/tests/test_pagure_flask_rebase.py b/tests/test_pagure_flask_rebase.py index 240047f..2284339 100644 --- a/tests/test_pagure_flask_rebase.py +++ b/tests/test_pagure_flask_rebase.py @@ -68,6 +68,7 @@ class PagureRebasetests(tests.Modeltests): branch_to="master", title="PR from the test branch", user="pingou", + allow_rebase=True, ) self.session.commit() self.assertEqual(req.id, 1) @@ -400,5 +401,153 @@ class PagureRebasetests(tests.Modeltests): ) +class PagureRebaseNotAllowedtests(tests.Modeltests): + """ Tests rebasing pull-request in pagure """ + + maxDiff = None + + @patch("pagure.lib.notify.send_email", MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureRebaseNotAllowedtests, self).setUp() + + pagure.config.config["REQUESTS_FOLDER"] = None + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, "repos"), bare=True) + tests.create_projects_git( + os.path.join(self.path, "requests"), bare=True + ) + tests.add_content_to_git( + os.path.join(self.path, "repos", "test.git"), + branch="master", + content="foobarbaz", + filename="testfile", + ) + tests.add_content_to_git( + os.path.join(self.path, "repos", "test.git"), + branch="test", + content="foobar", + filename="sources", + ) + tests.add_readme_git_repo(os.path.join(self.path, "repos", "test.git")) + + # Create a PR for these changes + project = pagure.lib.query.get_authorized_project(self.session, "test") + req = pagure.lib.query.new_pull_request( + session=self.session, + repo_from=project, + branch_from="test", + repo_to=project, + branch_to="master", + title="PR from the test branch", + user="pingou", + allow_rebase=False, + ) + self.session.commit() + self.assertEqual(req.id, 1) + self.assertEqual(req.title, "PR from the test branch") + + self.project = pagure.lib.query.get_authorized_project( + self.session, "test" + ) + self.assertEqual(len(project.requests), 1) + self.request = self.project.requests[0] + + def test_rebase_api_ui_logged_in(self): + """ Test the rebase PR API endpoint when logged in from the UI and + its outcome. """ + + user = tests.FakeUser(username="pingou") + with tests.user_set(self.app.application, user): + # Get the merge status first so it's cached and can be refreshed + csrf_token = self.get_csrf() + data = {"requestid": self.request.uid, "csrf_token": csrf_token} + output = self.app.post("/pv/pull-request/merge", data=data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual( + data, + { + "code": "MERGE", + "message": "The pull-request can be merged with " + "a merge commit", + "short_code": "With merge", + }, + ) + + output = self.app.post("/api/0/test/pull-request/1/rebase") + self.assertEqual(output.status_code, 403) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual( + data, + { + "error": "You are not authorized to rebase this pull-request", + "error_code": "EREBASENOTALLOWED", + }, + ) + + def test_rebase_api_ui_logged_in_different_user(self): + """ Test the rebase PR API endpoint when logged in from the UI and + its outcome. """ + # Add 'foo' to the project 'test' so 'foo' can rebase the PR + repo = pagure.lib.query._get_project(self.session, "test") + msg = pagure.lib.query.add_user_to_project( + session=self.session, project=repo, new_user="foo", user="pingou" + ) + self.session.commit() + self.assertEqual(msg, "User added") + + user = tests.FakeUser(username="foo") + with tests.user_set(self.app.application, user): + # Get the merge status first so it's cached and can be refreshed + csrf_token = self.get_csrf() + data = {"requestid": self.request.uid, "csrf_token": csrf_token} + output = self.app.post("/pv/pull-request/merge", data=data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual( + data, + { + "code": "MERGE", + "message": "The pull-request can be merged with " + "a merge commit", + "short_code": "With merge", + }, + ) + + output = self.app.post("/api/0/test/pull-request/1/rebase") + self.assertEqual(output.status_code, 403) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual( + data, + { + "error": "You are not authorized to rebase this pull-request", + "error_code": "EREBASENOTALLOWED", + }, + ) + + def test_rebase_api_api_logged_in(self): + """ Test the rebase PR API endpoint when using an API token and + its outcome. """ + + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + headers = {"Authorization": "token aaabbbcccddd"} + + output = self.app.post( + "/api/0/test/pull-request/1/rebase", headers=headers + ) + self.assertEqual(output.status_code, 403) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual( + data, + { + "error": "You are not authorized to rebase this pull-request", + "error_code": "EREBASENOTALLOWED", + }, + ) + + if __name__ == "__main__": unittest.main(verbosity=2)