Browse Source

Add support for allowing the maintainers of the target project rebase

If the person opening the PR checks this checkbox, pagure will by-pass
the auth check when pushing to the project the PR originates from and
thus allow rebasing.
Otherwise, rebase would only be allowed on project the maintainer has
commit access to, which is likely not the case for most forks.
In addition, since we do not know what the fork is used for, it could be
that the fork is used by the contributor as a basis for their own
deployment, we want the permission to rebase the fork to be explicit to
avoid changing the fork without the contributor's knowledge.

Fixes https://pagure.io/pagure/issue/4456

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
Pierre-Yves Chibon 5 years ago
parent
commit
e180e7ed38

+ 34 - 0
alembic/versions/d7589827abbb_add_support_for_allow_rebase.py

@@ -0,0 +1,34 @@
+"""Add support for allow_rebase
+
+Revision ID: d7589827abbb
+Revises: 802047d28f89
+Create Date: 2019-05-09 16:25:58.971712
+
+"""
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'd7589827abbb'
+down_revision = '802047d28f89'
+
+
+def upgrade():
+    ''' Add the column allow_rebase to the table pull_requests.
+    '''
+    op.add_column(
+        'pull_requests',
+        sa.Column('allow_rebase', sa.Boolean, default=False, nullable=True)
+    )
+    op.execute('''UPDATE "pull_requests" SET allow_rebase=False;''')
+    op.alter_column(
+        'pull_requests', 'allow_rebase',
+        nullable=False, existing_nullable=True)
+
+
+def downgrade():
+    ''' Remove the column allow_rebase from the table pull_requests.
+    '''
+    op.drop_column('pull_requests', 'allow_rebase')

+ 5 - 0
pagure/forms.py

@@ -315,6 +315,11 @@ class RequestPullForm(PagureForm):
     initial_comment = wtforms.TextAreaField(
         "Initial Comment", [wtforms.validators.Optional()]
     )
+    allow_rebase = wtforms.BooleanField(
+        "Allow rebasing",
+        [wtforms.validators.Optional()],
+        false_values=FALSE_VALUES,
+    )
 
 
 class RemoteRequestPullForm(RequestPullForm):

+ 17 - 7
pagure/lib/git.py

@@ -1964,13 +1964,23 @@ def rebase_pull_request(session, request, username):
         # Push the changes
         _log.info("Pushing %s to %s", branch_ref.name, request.branch_from)
         try:
-            tempclone.push(
-                username,
-                branch_ref.name,
-                request.branch_from,
-                pull_request=request,
-                force=True,
-            )
+            if request.allow_rebase:
+                tempclone.push(
+                    username,
+                    branch_ref.name,
+                    request.branch_from,
+                    pull_request=request,
+                    force=True,
+                    internal="yes",
+                )
+            else:
+                tempclone.push(
+                    username,
+                    branch_ref.name,
+                    request.branch_from,
+                    pull_request=request,
+                    force=True,
+                )
         except subprocess.CalledProcessError as err:
             _log.debug(
                 "Rebase FAILED: {cmd} returned code {code} with the "

+ 2 - 0
pagure/lib/model.py

@@ -1960,6 +1960,8 @@ class PullRequest(BASE):
         nullable=True,
     )
 
+    allow_rebase = sa.Column(sa.Boolean, default=False, nullable=False)
+
     # While present this column isn't used anywhere yet
     private = sa.Column(sa.Boolean, nullable=False, default=False)
 

+ 2 - 0
pagure/lib/query.py

@@ -1859,6 +1859,7 @@ def new_pull_request(
     title,
     user,
     initial_comment=None,
+    allow_rebase=False,
     repo_from=None,
     remote_git=None,
     requestuid=None,
@@ -1887,6 +1888,7 @@ def new_pull_request(
         branch_from=branch_from,
         title=title,
         initial_comment=initial_comment or None,
+        allow_rebase=allow_rebase,
         user_id=user_obj.id,
         status=status,
         commit_start=commit_start,

+ 9 - 0
pagure/templates/repo_new_pull_request.html

@@ -208,6 +208,15 @@
           {% endif %}
           <div id="preview" class="p-1">
           </div>
+          <div class="form-control">
+            <label for="allow_rebase">Allow rebasing</label>
+            <label class="c-input c-checkbox">
+              <input checked id="allow_rebase" name="allow_rebase" type="checkbox" value="y">
+            </label>
+            <small class="text-muted">
+              Let the maintainer of the target project to rebase the pull-request
+            </small>
+          </div>
         </div>
         <div class="card-footer bg-light">
           <div class="d-flex align-items-center">

+ 1 - 1
pagure/templates/repo_pull_request.html

@@ -179,7 +179,7 @@
           </a>
           <div id="merge-alert" class="text-xs-center dropdown-menu dropdown-menu-right p-0" style="min-width:400px">
              <div class="alert text-center mb-0">
-                {% if pull_request.status == 'Open' and g.repo_committer %}
+                {% if pull_request.status == 'Open' and g.repo_committer and pull_request.allow_rebase %}
                 <small id="merge-alert-message"></small>
                 <form action="{{ url_for('ui_ns.merge_request_pull',
                         repo=repo.name,

+ 3 - 0
pagure/ui/fork.py

@@ -1712,6 +1712,7 @@ def new_request_pull(
                 repo_from=repo,
                 title=form.title.data,
                 initial_comment=initial_comment,
+                allow_rebase=form.allow_rebase.data,
                 user=flask.g.fas_user.username,
                 commit_start=commit_start,
                 commit_stop=commit_stop,
@@ -1756,6 +1757,8 @@ def new_request_pull(
 
     if not flask.g.repo_committer:
         form = None
+    elif flask.request.method == "GET":
+        form.allow_rebase.data = True
 
     # if the pull request we are creating only has one commit,
     # we automatically fill out the form fields for the PR with