diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e78615e3c2930478a4049b006324509accccaf7c..295f9bca24b05f5d83864bd13d376d8adbb2e35c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -349,7 +349,7 @@ on those issues. Please select someone with relevant experience from the
 [GitLab team][team]. If there is nobody mentioned with that expertise look in
 the commit history for the affected files to find someone.
 
-[described in our handbook]: https://about.gitlab.com/handbook/engineering/issues/issue-triage-policies/
+[described in our handbook]: https://about.gitlab.com/handbook/engineering/issue-triage/
 [issue bash events]: https://gitlab.com/gitlab-org/gitlab-ce/issues/17815
 
 ### Feature proposals
diff --git a/PROCESS.md b/PROCESS.md
index f206506f7c5c8a3fb6ec4e0517eeee344cdcd68f..7438df8014bb005b399189af6220b90c8a16ae68 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -168,6 +168,7 @@ the stable branch are:
 
 * Fixes for [regressions](#regressions)
 * Fixes for security issues
+* Fixes or improvements to automated QA scenarios
 * New or updated translations (as long as they do not touch application code)
 
 During the feature freeze all merge requests that are meant to go into the
diff --git a/README.md b/README.md
index 0266fe82c82dd9881666b42f4319e7f3666e73dc..8bd667b3dac30f08f2a1619444c45b27db760673 100644
--- a/README.md
+++ b/README.md
@@ -126,5 +126,5 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on
 
 ## Is it awesome?
 
-Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
 [These people](https://twitter.com/gitlab/likes) seem to like it.
+
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index f69fe03fcb3772d5e3b6b1688162e1e9934137ce..c20d07a169db37f0871bb8d90d301df605b34be4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -265,10 +265,10 @@ export default {
       />
 
       <section
-        v-if="mr.maintainerEditAllowed"
+        v-if="mr.allowCollaboration"
         class="mr-info-list mr-links"
       >
-        {{ s__("mrWidget|Allows edits from maintainers") }}
+        {{ s__("mrWidget|Allows commits from members who can merge to the target branch") }}
       </section>
 
       <mr-widget-related-links
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index e5b7e1f1c68170674364422567f174313c784fbb..134aaacf9d21d1906c1be9be7c4676dc6d0d85a4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -83,7 +83,7 @@ export default class MergeRequestStore {
     this.canBeMerged = data.can_be_merged || false;
     this.isMergeAllowed = data.mergeable || false;
     this.mergeOngoing = data.merge_ongoing;
-    this.maintainerEditAllowed = data.allow_maintainer_to_push;
+    this.allowCollaboration = data.allow_collaboration;
 
     // Cherry-pick and Revert actions related
     this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 22fc5757447f1a49ec01c8b934bb82aa868999ec..6f231619f265533c0682cbcf0a102a0f8f9104c5 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -124,15 +124,18 @@
             break;
         }
       },
+      hideOnSmallScreen(item) {
+        return !item.first && !item.last && !item.next && !item.prev && !item.active;
+      },
     },
   };
 </script>
 <template>
   <div
     v-if="showPagination"
-    class="gl-pagination"
+    class="gl-pagination prepend-top-default"
   >
-    <ul class="pagination clearfix">
+    <ul class="pagination justify-content-center">
       <li
         v-for="(item, index) in getItems"
         :key="index"
@@ -142,12 +145,17 @@
           'js-next-button': item.next,
           'js-last-button': item.last,
           'js-first-button': item.first,
+          'd-none d-md-block': hideOnSmallScreen(item),
           separator: item.separator,
           active: item.active,
-          disabled: item.disabled
+          disabled: item.disabled || item.separator
         }"
+        class="page-item"
       >
-        <a @click.prevent="changePage(item.title, item.disabled)">
+        <a
+          @click.prevent="changePage(item.title, item.disabled)"
+          class="page-link"
+        >
           {{ item.title }}
         </a>
       </li>
diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss
index d5679177f8fccdf3becf67f7e48265846e32c814..fc4a4250acc489831a4d2a7902db330ff40e4f27 100644
--- a/app/assets/stylesheets/bootstrap_migration.scss
+++ b/app/assets/stylesheets/bootstrap_migration.scss
@@ -24,6 +24,11 @@ html {
   font-size: 14px;
 }
 
+legend {
+  border-bottom: 1px solid $border-color;
+  margin-bottom: 20px;
+}
+
 button,
 html [type="button"],
 [type="reset"],
@@ -183,7 +188,9 @@ table {
 
 .nav-tabs {
   .nav-link {
-    border: 0;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
   }
 
   .nav-item {
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 0536c39cee71ea20e3047af0a4150fbc72041601..55c0bc76f238e692b9ecc9520ad5f4b2cc8c4477 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -115,9 +115,3 @@ body {
 .with-performance-bar .layout-page {
   margin-top: $header-height + $performance-bar-height;
 }
-
-.vertical-center {
-  min-height: 100vh;
-  display: flex;
-  align-items: center;
-}
diff --git a/app/assets/stylesheets/framework/pagination.scss b/app/assets/stylesheets/framework/pagination.scss
index d3e013590b68c2753bb6fd7b49b361238782cd39..50a1b1c446dca80c567f4322ac54d7e6ed7a41db 100644
--- a/app/assets/stylesheets/framework/pagination.scss
+++ b/app/assets/stylesheets/framework/pagination.scss
@@ -1,91 +1,6 @@
 .gl-pagination {
-  text-align: center;
-  border-top: 1px solid $border-color;
-  margin: 0;
-  margin-top: 0;
-
-  .pagination {
-    padding: 0;
-    margin: 20px 0;
-
-    a {
-      cursor: pointer;
-    }
-
-    .separator,
-    .separator:hover {
-      a {
-        cursor: default;
-        background-color: $gray-light;
-        padding: $gl-vert-padding;
-      }
-    }
-  }
-
-
-  .gap,
-  .gap:hover {
-    background-color: $gray-light;
-    padding: $gl-vert-padding;
-    cursor: default;
-  }
-}
-
-.card > .gl-pagination {
-  margin: 0;
-}
-
-/**
- * Extra-small screen pagination.
- */
-@media (max-width: 320px) {
-  .gl-pagination {
-    .first,
-    .last {
-      display: none;
-    }
-
-    .page-item {
-      display: none;
-
-      &.active {
-        display: inline;
-      }
-    }
-  }
-}
-
-/**
- * Small screen pagination
- */
-@include media-breakpoint-down(xs) {
-  .gl-pagination {
-    .pagination li a {
-      padding: 6px 10px;
-    }
-
-    .page-item {
-      display: none;
-
-      &.active {
-        display: inline;
-      }
-    }
-  }
-}
-
-/**
- * Medium screen pagination
- */
-@media (min-width: map-get($grid-breakpoints, xs)) and (max-width: map-get($grid-breakpoints, sm)) {
-  .gl-pagination {
-    .page-item {
-      display: none;
-
-      &.active,
-      &.sibling {
-        display: inline;
-      }
-    }
+  a {
+    color: inherit;
+    text-decoration: none;
   }
 }
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 4aea97407353177428da5941b59d7bff82a7010f..b42c232fd912b572d633ede1f72a7217b3d5d7e3 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -485,6 +485,15 @@
     .sidebar-collapsed-user {
       padding-bottom: 0;
       margin-bottom: 10px;
+
+      .author_link {
+        padding-left: 0;
+
+        .avatar {
+          position: static;
+          margin: 0;
+        }
+      }
     }
 
     .issuable-header-btn {
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index db8a8cdc0d2dd523265576b20b14c14241b81a8e..bc60a0a02e8cb831ed5d188c21a756823d39cff4 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -130,12 +130,17 @@ class ApplicationController < ActionController::Base
   end
 
   def access_denied!(message = nil)
+    # If we display a custom access denied message to the user, we don't want to
+    # hide existence of the resource, rather tell them they cannot access it using
+    # the provided message
+    status = message.present? ? :forbidden : :not_found
+
     respond_to do |format|
-      format.any { head :not_found }
+      format.any { head status }
       format.html do
         render "errors/access_denied",
                layout: "errors",
-               status: 404,
+               status: status,
                locals: { message: message }
       end
     end
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 29632bef7e55b10582842fd189d983470c828175..8e4aeec16dc524438bdb57d3183e0d85f40c4ffa 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -15,7 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
 
   def merge_request_params_attributes
     [
-      :allow_maintainer_to_push,
+      :allow_collaboration,
       :assignee_id,
       :description,
       :force_remove_source_branch,
diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb
index ab685b9106efb6c363e426d2e76b138f51e3e1d3..f7c6d1d59dba40b91428eb65aedbede8f91d6ab5 100644
--- a/app/controllers/users/terms_controller.rb
+++ b/app/controllers/users/terms_controller.rb
@@ -13,6 +13,10 @@ module Users
 
     def index
       @redirect = redirect_path
+
+      if @term.accepted_by_user?(current_user)
+        flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}"
+      end
     end
 
     def accept
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 74251c260f0ec0fc1eb4ecceeea80d04d7662dfd..5ff06b3e0fc681ea49d8d17a88424a43a83db5c8 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -126,8 +126,8 @@ module MergeRequestsHelper
     link_to(url[merge_request.project, merge_request], data: data_attrs, &block)
   end
 
-  def allow_maintainer_push_unavailable_reason(merge_request)
-    return if merge_request.can_allow_maintainer_to_push?(current_user)
+  def allow_collaboration_unavailable_reason(merge_request)
+    return if merge_request.can_allow_collaboration?(current_user)
 
     minimum_visibility = [merge_request.target_project.visibility_level,
                           merge_request.source_project.visibility_level].min
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index dfca799a53deafb0813f3d9dfa519c849d189c67..eb8d46f59f7f74166ca346d9cf85dd75dc5c4d6a 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -412,7 +412,10 @@ module ProjectsHelper
     exports_path = File.join(Settings.shared['path'], 'tmp/project_exports')
     filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]")
 
-    disk_path = Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
+    disk_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
+    end
+
     filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]")
   end
 
diff --git a/app/models/application_setting/term.rb b/app/models/application_setting/term.rb
index e8ce0ccbb719ffefa66ade7974493cea25bd5fb5..3b1dfe7e4efda73bb9f025754feeeb81a2ccfcfc 100644
--- a/app/models/application_setting/term.rb
+++ b/app/models/application_setting/term.rb
@@ -1,6 +1,7 @@
 class ApplicationSetting
   class Term < ActiveRecord::Base
     include CacheMarkdownField
+    has_many :term_agreements
 
     validates :terms, presence: true
 
@@ -9,5 +10,10 @@ class ApplicationSetting
     def self.latest
       order(:id).last
     end
+
+    def accepted_by_user?(user)
+      user.accepted_term_id == id ||
+        term_agreements.accepted.where(user: user).exists?
+    end
   end
 end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 57edd6a49569c004d38ac57816050ca15ae5d8a5..8c9aacca8de13340d55eb00c564d47c7328cde8b 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -219,10 +219,8 @@ module Ci
 
       cache_attributes(values)
 
-      if persist_cached_data?
-        self.assign_attributes(values)
-        self.save if self.changed?
-      end
+      # We save data without validation, it will always change due to `contacted_at`
+      self.update_columns(values) if persist_cached_data?
     end
 
     def pick_build!(build)
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 13246a774e3d99e3db892f523273441166061b19..095897b08e3b15877834c3754e76bda4518b1d54 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -4,11 +4,14 @@ module Avatarable
   included do
     prepend ShadowMethods
     include ObjectStorage::BackgroundMove
+    include Gitlab::Utils::StrongMemoize
 
     validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
     validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
 
     mount_uploader :avatar, AvatarUploader
+
+    after_initialize :add_avatar_to_batch
   end
 
   module ShadowMethods
@@ -18,6 +21,17 @@ module Avatarable
 
       avatar_path(only_path: args.fetch(:only_path, true)) || super
     end
+
+    def retrieve_upload(identifier, paths)
+      upload = retrieve_upload_from_batch(identifier)
+
+      # This fallback is needed when deleting an upload, because we may have
+      # already been removed from the DB. We have to check an explicit `#nil?`
+      # because it's a BatchLoader instance.
+      upload = super if upload.nil?
+
+      upload
+    end
   end
 
   def avatar_type
@@ -52,4 +66,37 @@ module Avatarable
 
     url_base + avatar.local_url
   end
+
+  # Path that is persisted in the tracking Upload model. Used to fetch the
+  # upload from the model.
+  def upload_paths(identifier)
+    avatar_mounter.blank_uploader.store_dirs.map { |store, path| File.join(path, identifier) }
+  end
+
+  private
+
+  def retrieve_upload_from_batch(identifier)
+    BatchLoader.for(identifier: identifier, model: self).batch(key: self.class) do |upload_params, loader, args|
+      model_class = args[:key]
+      paths = upload_params.flat_map do |params|
+        params[:model].upload_paths(params[:identifier])
+      end
+
+      Upload.where(uploader: AvatarUploader, path: paths).find_each do |upload|
+        model = model_class.instantiate('id' => upload.model_id)
+
+        loader.call({ model: model, identifier: File.basename(upload.path) }, upload)
+      end
+    end
+  end
+
+  def add_avatar_to_batch
+    return unless avatar_mounter
+
+    avatar_mounter.read_identifiers.each { |identifier| retrieve_upload_from_batch(identifier) }
+  end
+
+  def avatar_mounter
+    strong_memoize(:avatar_mounter) { _mounter(:avatar) }
+  end
 end
diff --git a/app/models/concerns/with_uploads.rb b/app/models/concerns/with_uploads.rb
index e7cfffb775b688b22ca546142c1425a085f99c6e..4245d083a49c0377681417c37524f42c844c0fb6 100644
--- a/app/models/concerns/with_uploads.rb
+++ b/app/models/concerns/with_uploads.rb
@@ -36,4 +36,8 @@ module WithUploads
       upload.destroy
     end
   end
+
+  def retrieve_upload(_identifier, paths)
+    uploads.find_by(path: paths)
+  end
 end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 4c1628d2bdb33f27eab7c5f76abc63f97add2301..535a2c362f24e8f94d35046df341e341610c47d1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1125,21 +1125,21 @@ class MergeRequest < ActiveRecord::Base
     project.merge_requests.merged.where(author_id: author_id).empty?
   end
 
-  def allow_maintainer_to_push
-    maintainer_push_possible? && super
+  def allow_collaboration
+    collaborative_push_possible? && super
   end
 
-  alias_method :allow_maintainer_to_push?, :allow_maintainer_to_push
+  alias_method :allow_collaboration?, :allow_collaboration
 
-  def maintainer_push_possible?
+  def collaborative_push_possible?
     source_project.present? && for_fork? &&
       target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
       source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
       !ProtectedBranch.protected?(source_project, source_branch)
   end
 
-  def can_allow_maintainer_to_push?(user)
-    maintainer_push_possible? &&
+  def can_allow_collaboration?(user)
+    collaborative_push_possible? &&
       Ability.allowed?(user, :push_code, source_project)
   end
 
diff --git a/app/models/note.rb b/app/models/note.rb
index 02f7a9b1e4f7cd94c59943561b5397f0e250cab2..41c04ae0571eeab75dd5800619ed8cc6582d0794 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -435,6 +435,10 @@ class Note < ActiveRecord::Base
     super.merge(noteable: noteable)
   end
 
+  def retrieve_upload(_identifier, paths)
+    Upload.find_by(model: self, path: paths)
+  end
+
   private
 
   def keep_around_commit
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
index 82c1c4de3a0fcbfc82632eac332ddc54620914df..355624fd552affd9a77d81b146ca40419fb6e4e3 100644
--- a/app/models/personal_snippet.rb
+++ b/app/models/personal_snippet.rb
@@ -1,2 +1,3 @@
 class PersonalSnippet < Snippet
+  include WithUploads
 end
diff --git a/app/models/project.rb b/app/models/project.rb
index b91a30400b7f773ae4f8a8d5c130f58eba600d3c..562198e2369f5d632d75ae031edd5d53c65895a9 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1975,18 +1975,18 @@ class Project < ActiveRecord::Base
                                 .limit(1)
                                 .select(1)
     source_of_merge_requests.opened
-      .where(allow_maintainer_to_push: true)
+      .where(allow_collaboration: true)
       .where('EXISTS (?)', developer_access_exists)
   end
 
-  def branch_allows_maintainer_push?(user, branch_name)
+  def branch_allows_collaboration?(user, branch_name)
     return false unless user
 
     cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push"
 
-    memoized_results = strong_memoize(:branch_allows_maintainer_push) do
+    memoized_results = strong_memoize(:branch_allows_collaboration) do
       Hash.new do |result, cache_key|
-        result[cache_key] = fetch_branch_allows_maintainer_push?(user, branch_name)
+        result[cache_key] = fetch_branch_allows_collaboration?(user, branch_name)
       end
     end
 
@@ -2128,18 +2128,18 @@ class Project < ActiveRecord::Base
     raise ex
   end
 
-  def fetch_branch_allows_maintainer_push?(user, branch_name)
+  def fetch_branch_allows_collaboration?(user, branch_name)
     check_access = -> do
       next false if empty_repo?
 
       merge_request = source_of_merge_requests.opened
-                        .where(allow_maintainer_to_push: true)
+                        .where(allow_collaboration: true)
                         .find_by(source_branch: branch_name)
       merge_request&.can_be_merged_by?(user)
     end
 
     if RequestStore.active?
-      RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_maintainer_push") do
+      RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do
         check_access.call
       end
     else
diff --git a/app/models/term_agreement.rb b/app/models/term_agreement.rb
index 8458a231bbddd3321c08b3e2e9bcec015f46b548..c317bd0c90be40c9338789ebe14743eefa81549a 100644
--- a/app/models/term_agreement.rb
+++ b/app/models/term_agreement.rb
@@ -2,5 +2,7 @@ class TermAgreement < ActiveRecord::Base
   belongs_to :term, class_name: 'ApplicationSetting::Term'
   belongs_to :user
 
+  scope :accepted, -> { where(accepted: true) }
+
   validates :user, :term, presence: true
 end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index 8b65758f3e8202085ffdd4ec4a2b702e3879b559..1c0cc7425eca8e5b063e872ab8a7da371fd923d6 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -14,8 +14,8 @@ module Ci
       @subject.triggered_by?(@user)
     end
 
-    condition(:branch_allows_maintainer_push) do
-      @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+    condition(:branch_allows_collaboration) do
+      @subject.project.branch_allows_collaboration?(@user, @subject.ref)
     end
 
     rule { protected_ref }.policy do
@@ -25,7 +25,7 @@ module Ci
 
     rule { can?(:admin_build) | (can?(:update_build) & owner_of_job) }.enable :erase_build
 
-    rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+    rule { can?(:public_access) & branch_allows_collaboration }.policy do
       enable :update_build
       enable :update_commit_status
     end
diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb
index 540e4235299f0e5c4de8e528095b408f19b1c486..b81329d06256da33646c67948b156eb7634f2c15 100644
--- a/app/policies/ci/pipeline_policy.rb
+++ b/app/policies/ci/pipeline_policy.rb
@@ -4,13 +4,13 @@ module Ci
 
     condition(:protected_ref) { ref_protected?(@user, @subject.project, @subject.tag?, @subject.ref) }
 
-    condition(:branch_allows_maintainer_push) do
-      @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+    condition(:branch_allows_collaboration) do
+      @subject.project.branch_allows_collaboration?(@user, @subject.ref)
     end
 
     rule { protected_ref }.prevent :update_pipeline
 
-    rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+    rule { can?(:public_access) & branch_allows_collaboration }.policy do
       enable :update_pipeline
     end
 
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 141070aef4567208da10f43b2d99e8ca150380eb..8260c6c7b84095a0239f843608322a6e362d40bf 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -13,7 +13,7 @@ class MergeRequestWidgetEntity < IssuableEntity
   expose :squash
   expose :target_branch
   expose :target_project_id
-  expose :allow_maintainer_to_push
+  expose :allow_collaboration
 
   expose :should_be_rebased?, as: :should_be_rebased
   expose :ff_only_enabled do |merge_request|
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index e70445cfb671a1b91d1eae315f31f8673735c0b9..7bcb8f49d0d51cf27f3926a88de8fc8a9b89f818 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -1,5 +1,7 @@
 module ApplicationSettings
   class UpdateService < ApplicationSettings::BaseService
+    attr_reader :params, :application_setting
+
     def execute
       update_terms(@params.delete(:terms))
 
diff --git a/app/services/applications/create_service.rb b/app/services/applications/create_service.rb
index 35d45f25a715ca60e9796850d366df9c62f65e93..e67af929954abbb19b3bca4348859471e133e81a 100644
--- a/app/services/applications/create_service.rb
+++ b/app/services/applications/create_service.rb
@@ -2,8 +2,7 @@ module Applications
   class CreateService
     def initialize(current_user, params)
       @current_user = current_user
-      @params = params
-      @ip_address = @params.delete(:ip_address)
+      @params = params.except(:ip_address)
     end
 
     def execute(request = nil)
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 231ab76fde48931c57a5ce85eb365c4dc6c08d72..4c420b3825831f794160b54e5eebd3411c94273c 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -38,8 +38,8 @@ module MergeRequests
     def filter_params(merge_request)
       super
 
-      unless merge_request.can_allow_maintainer_to_push?(current_user)
-        params.delete(:allow_maintainer_to_push)
+      unless merge_request.can_allow_collaboration?(current_user)
+        params.delete(:allow_collaboration)
       end
     end
 
diff --git a/app/services/test_hooks/project_service.rb b/app/services/test_hooks/project_service.rb
index 01d5d774cd5ca1b8b1da0d50693e9e4386ba0969..65183e84ccee86028aac760cdbbed6ffe6bef0af 100644
--- a/app/services/test_hooks/project_service.rb
+++ b/app/services/test_hooks/project_service.rb
@@ -1,11 +1,13 @@
 module TestHooks
   class ProjectService < TestHooks::BaseService
-    private
+    attr_writer :project
 
     def project
       @project ||= hook.project
     end
 
+    private
+
     def push_events_data
       throw(:validation_error, 'Ensure the project has at least one commit.') if project.empty_repo?
 
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 3bb2e1ea63a66aaa8b8d442525180b20a7573585..5aa1bc7227c8096118f5670c52e75114a0190894 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -33,7 +33,7 @@ module ObjectStorage
 
         unless current_upload_satisfies?(paths, model)
           # the upload we already have isn't right, find the correct one
-          self.upload = uploads.find_by(model: model, path: paths)
+          self.upload = model&.retrieve_upload(identifier, paths)
         end
 
         super
@@ -46,7 +46,7 @@ module ObjectStorage
       end
 
       def upload=(upload)
-        return unless upload
+        return if upload.nil?
 
         self.object_store = upload.store
         super
diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml
index 35a331283ab5e564c42881c380f3b7c290fe3581..04acc5f8423ba62ef8bc1d75b805436a42fdec1f 100644
--- a/app/views/admin/users/_access_levels.html.haml
+++ b/app/views/admin/users/_access_levels.html.haml
@@ -1,26 +1,26 @@
 %fieldset
   %legend Access
-  .form-group
-    = f.label :projects_limit, class: 'col-form-label'
+  .form-group.row
+    = f.label :projects_limit, class: 'col-form-label col-sm-2'
     .col-sm-10= f.number_field :projects_limit, min: 0, max: Gitlab::Database::MAX_INT_VALUE, class: 'form-control'
 
-  .form-group
-    = f.label :can_create_group, class: 'col-form-label'
+  .form-group.row
+    = f.label :can_create_group, class: 'col-form-label col-sm-2'
     .col-sm-10= f.check_box :can_create_group
 
-  .form-group
-    = f.label :access_level, class: 'col-form-label'
+  .form-group.row
+    = f.label :access_level, class: 'col-form-label col-sm-2'
     .col-sm-10
       - editing_current_user = (current_user == @user)
 
       = f.radio_button :access_level, :regular, disabled: editing_current_user
-      = label_tag :regular do
+      = label_tag :regular, class: 'font-weight-bold' do
         Regular
       %p.light
         Regular users have access to their groups and projects
 
       = f.radio_button :access_level, :admin, disabled: editing_current_user
-      = label_tag :admin do
+      = label_tag :admin, class: 'font-weight-bold' do
         Admin
       %p.light
         Administrators have access to all groups, projects and users and can manage all features in this installation
@@ -28,8 +28,8 @@
         %p.light
           You cannot remove your own admin rights.
 
-  .form-group
-    = f.label :external, class: 'col-form-label'
+  .form-group.row
+    = f.label :external, class: 'col-form-label col-sm-2'
     .col-sm-10
       = f.check_box :external do
         External
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 010cb2ac3549dfd2e4b8c46169e59b26f33c67b9..58be07fc83eaf0c6a7d9c1c5d6304ea1a78fb66c 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -56,7 +56,7 @@
         = f.label :linkedin, class: 'col-form-label col-sm-2'
         .col-sm-10= f.text_field :linkedin, class: 'form-control'
       .form-group.row
-        = f.label :twitter, class: 'col-form-label'
+        = f.label :twitter, class: 'col-form-label col-sm-2'
         .col-sm-10= f.text_field :twitter, class: 'form-control'
       .form-group.row
         = f.label :website_url, 'Website', class: 'col-form-label col-sm-2'
diff --git a/app/views/kaminari/gitlab/_first_page.html.haml b/app/views/kaminari/gitlab/_first_page.html.haml
index 369165da02a17b954f622998493f44c14953fbb3..3b7d4a1c5781838d7bfad86dc3fdf6d30fac2c73 100644
--- a/app/views/kaminari/gitlab/_first_page.html.haml
+++ b/app/views/kaminari/gitlab/_first_page.html.haml
@@ -5,5 +5,5 @@
 -#    total_pages:   total number of pages
 -#    per_page:      number of items to fetch per page
 -#    remote:        data-remote
-%li.first.page-item
+%li.page-item.js-first-button
   = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_gap.html.haml b/app/views/kaminari/gitlab/_gap.html.haml
index 6eec30212d19a19626ffb0155ac6a6c25d91be84..849f92fdc9590f61e8c86c26671373ddc10ec45a 100644
--- a/app/views/kaminari/gitlab/_gap.html.haml
+++ b/app/views/kaminari/gitlab/_gap.html.haml
@@ -4,5 +4,5 @@
 -#    total_pages:   total number of pages
 -#    per_page:      number of items to fetch per page
 -#    remote:        data-remote
-%li.page-item.disabled
+%li.page-item.disabled.d-none.d-md-block
   = link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_last_page.html.haml b/app/views/kaminari/gitlab/_last_page.html.haml
index 8b49db5828174cd07b8c6dac1f609ae8eb48be85..7836e17f87731721ebddc5bff6cd296cbfdb802e 100644
--- a/app/views/kaminari/gitlab/_last_page.html.haml
+++ b/app/views/kaminari/gitlab/_last_page.html.haml
@@ -5,5 +5,5 @@
 -#    total_pages:   total number of pages
 -#    per_page:      number of items to fetch per page
 -#    remote:        data-remote
-%li.last.page-item
+%li.page-item.js-last-button
   = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote, class: 'page-link'}
diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml
index 05f151555ad93d2a61465ebb906c4dc4d595d7e3..a7fa1a21a6c977fd08684008e52a09f26bc8b05b 100644
--- a/app/views/kaminari/gitlab/_next_page.html.haml
+++ b/app/views/kaminari/gitlab/_next_page.html.haml
@@ -8,5 +8,5 @@
 
 - page_url = current_page.last? ? '#' : url
 
-%li.page-item{ class: ('disabled' if current_page.last?) }
+%li.page-item.js-next-button{ class: ('disabled' if current_page.last?) }
   = link_to raw(t 'views.pagination.next'), page_url, rel: 'next', remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_page.html.haml b/app/views/kaminari/gitlab/_page.html.haml
index 8a40e13a5374f31ab7a9e0a79b417901a88a6561..d0dc1784540d253695c41c1bc2e3225ae9d45db7 100644
--- a/app/views/kaminari/gitlab/_page.html.haml
+++ b/app/views/kaminari/gitlab/_page.html.haml
@@ -6,5 +6,5 @@
 -#    total_pages:   total number of pages
 -#    per_page:      number of items to fetch per page
 -#    remote:        data-remote
-%li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?)] }
+%li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?), ('d-none d-md-block' if !page.current?) ] }
   = link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: 'page-link' }
diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml
index a6435deb4bfdefc46f3a681cc7264c201e4545b1..ac9e274dbc76b1882029b9f7abe947624f35d354 100644
--- a/app/views/kaminari/gitlab/_paginator.html.haml
+++ b/app/views/kaminari/gitlab/_paginator.html.haml
@@ -6,7 +6,7 @@
 -#    remote:        data-remote
 -#    paginator:     the paginator that renders the pagination tags inside
 = paginator.render do
-  .gl-pagination
+  .gl-pagination.prepend-top-default
     %ul.pagination.justify-content-center
       - unless current_page.first?
         = first_page_tag unless total_pages < 5 # As kaminari will always show the first 5 pages
diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml
index f4a11a449b77276431aeb9411fb3d164b8daaf66..12b0e106a62e341f409387a15a767050e8851e84 100644
--- a/app/views/kaminari/gitlab/_prev_page.html.haml
+++ b/app/views/kaminari/gitlab/_prev_page.html.haml
@@ -8,5 +8,5 @@
 
 - page_url = current_page.first? ? '#' : url
 
-%li.page-item{ class: ('disabled' if current_page.first?) }
+%li.page-item.js-previous-button{ class: ('disabled' if current_page.first?) }
   = link_to raw(t 'views.pagination.previous'), page_url, rel: 'prev', remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_without_count.html.haml b/app/views/kaminari/gitlab/_without_count.html.haml
index 1425a8090520fef7c14312ebf76b13ba9b1c1a8c..f780400ebcb1b0a5f8bfdd9f73da3cc572d0adec 100644
--- a/app/views/kaminari/gitlab/_without_count.html.haml
+++ b/app/views/kaminari/gitlab/_without_count.html.haml
@@ -1,5 +1,5 @@
-.gl-pagination
-  %ul.pagination.clearfix
+.gl-pagination.prepend-top-default
+  %ul.pagination.justify-content-center
     - if previous_path
       %li.page-item.prev
         = link_to(t('views.pagination.previous'), previous_path, rel: 'prev', class: 'page-link')
diff --git a/app/views/projects/blob/viewers/_download.html.haml b/app/views/projects/blob/viewers/_download.html.haml
index f9b1da05a008505644a2641d0dcf325e94f93ee2..fda4b9c92cd9e0254cd93c8705a30a14f90d9ed5 100644
--- a/app/views/projects/blob/viewers/_download.html.haml
+++ b/app/views/projects/blob/viewers/_download.html.haml
@@ -1,5 +1,5 @@
 .file-content.blob_file.blob-no-preview
-  .center.render-error.vertical-center
+  .center.render-error
     = link_to blob_raw_path do
       %h1.light
         = sprite_icon('download')
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 35a09f06bfa5bd827b5e585ca4dfa3f6912a6fd3..5bb1bfb7059c5ef09383f9ec9d527c133d9c33a1 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -29,16 +29,16 @@
 
     .col-lg-9.js-toggle-container
       %ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
-        %li{ class: active_when(active_tab == 'blank'), role: 'presentation' }
-          %a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
+        %li.nav-item{ role: 'presentation' }
+          %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
             %span.d-none.d-sm-block Blank project
             %span.d-block.d-sm-none Blank
-        %li{ class: active_when(active_tab == 'template'), role: 'presentation' }
-          %a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
+        %li.nav-item{ role: 'presentation' }
+          %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
             %span.d-none.d-sm-block Create from template
             %span.d-block.d-sm-none Template
-        %li{ class: active_when(active_tab == 'import'), role: 'presentation' }
-          %a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
+        %li.nav-item{ role: 'presentation' }
+          %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
             %span.d-none.d-sm-block Import project
             %span.d-block.d-sm-none Import
 
diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml
index b34549240e0762ce3b1979ae1d80280b545e5c7e..519b5fae84645729607e1bb8f7105b94911dfc59 100644
--- a/app/views/shared/issuable/form/_contribution.html.haml
+++ b/app/views/shared/issuable/form/_contribution.html.haml
@@ -12,9 +12,9 @@
     = _('Contribution')
   .col-sm-10
     .form-check
-      = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user), class: 'form-check-input'
-      = form.label :allow_maintainer_to_push, class: 'form-check-label' do
-        = _('Allow edits from maintainers.')
-        = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access')
+      = form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input'
+      = form.label :allow_collaboration, class: 'form-check-label' do
+        = _('Allow commits from members who can merge to the target branch.')
+        = link_to 'About this feature', help_page_path('user/project/merge_requests/allow_collaboration')
         .form-text.text-muted
-          = allow_maintainer_push_unavailable_reason(issuable)
+          = allow_collaboration_unavailable_reason(issuable)
diff --git a/app/views/shared/projects/_edit_information.html.haml b/app/views/shared/projects/_edit_information.html.haml
index ec9dc8f62c2a40b99e4de6e609e78dbd10476daa..9230e045a81fdcc8468c2406a1c7b648866c9e3a 100644
--- a/app/views/shared/projects/_edit_information.html.haml
+++ b/app/views/shared/projects/_edit_information.html.haml
@@ -1,6 +1,6 @@
 - unless can?(current_user, :push_code, @project)
   .inline.prepend-left-10
-    - if @project.branch_allows_maintainer_push?(current_user, selected_branch)
+    - if @project.branch_allows_collaboration?(current_user, selected_branch)
       = commit_in_single_accessible_branch
     - else
       = commit_in_fork_help
diff --git a/app/views/users/terms/index.html.haml b/app/views/users/terms/index.html.haml
index b9f25a711705620bbc81202381eea4c8bf9adf54..33cddf63952e4c5570ded526049dbb29dfc57854 100644
--- a/app/views/users/terms/index.html.haml
+++ b/app/views/users/terms/index.html.haml
@@ -7,6 +7,10 @@
     .float-right
       = button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
         = _('Accept terms')
+  - else
+    .pull-right
+      = link_to root_path, class: 'btn btn-success prepend-left-8' do
+        = _('Continue')
   - if can?(current_user, :decline_terms, @term)
     .float-right
       = button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
diff --git a/changelogs/unreleased/42751-rename-mr-maintainer-push.yml b/changelogs/unreleased/42751-rename-mr-maintainer-push.yml
new file mode 100644
index 0000000000000000000000000000000000000000..aa29f6ed4b7985ca38d797eb700d3c91167fc89f
--- /dev/null
+++ b/changelogs/unreleased/42751-rename-mr-maintainer-push.yml
@@ -0,0 +1,5 @@
+---
+title: Rephrasing Merge Request's 'allow edits from maintainer' functionality
+merge_request: 19061
+author:
+type: deprecated
diff --git a/changelogs/unreleased/46585-gdpr-terms-acceptance.yml b/changelogs/unreleased/46585-gdpr-terms-acceptance.yml
new file mode 100644
index 0000000000000000000000000000000000000000..84853846b0e532eb3af555d05b4934afd0dfe84f
--- /dev/null
+++ b/changelogs/unreleased/46585-gdpr-terms-acceptance.yml
@@ -0,0 +1,6 @@
+---
+title: Add flash notice if user has already accepted terms and allow users to continue
+  to root path
+merge_request: 19156
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-avatars-n-plus-one.yml b/changelogs/unreleased/fix-avatars-n-plus-one.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c5b42071f2bd6c58f9dcdd545465c9c9996de719
--- /dev/null
+++ b/changelogs/unreleased/fix-avatars-n-plus-one.yml
@@ -0,0 +1,5 @@
+---
+title: Fix an N+1 when loading user avatars
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/optimise-runner-update-cached-info.yml b/changelogs/unreleased/optimise-runner-update-cached-info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..15fb9bcdf41b1521b8ba1eebe8cfef894309dbed
--- /dev/null
+++ b/changelogs/unreleased/optimise-runner-update-cached-info.yml
@@ -0,0 +1,5 @@
+---
+title: Update runner cached informations without performing validations
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/rd-44364-deprecate-support-for-dsa-keys.yml b/changelogs/unreleased/rd-44364-deprecate-support-for-dsa-keys.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1a52ffaaf79b4e88c5b355a48698030dd20e26d8
--- /dev/null
+++ b/changelogs/unreleased/rd-44364-deprecate-support-for-dsa-keys.yml
@@ -0,0 +1,5 @@
+---
+title: Add migration to disable the usage of DSA keys
+merge_request: 19299
+author:
+type: other
diff --git a/changelogs/unreleased/sh-fix-events-nplus-one.yml b/changelogs/unreleased/sh-fix-events-nplus-one.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e5a974bef305b89964ca6b013130fe895f3711fb
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-events-nplus-one.yml
@@ -0,0 +1,5 @@
+---
+title: Eliminate N+1 queries with authors and push_data_payload in Events API
+merge_request:
+author:
+type: performance
diff --git a/db/migrate/20180523042841_rename_merge_requests_allow_maintainer_to_push.rb b/db/migrate/20180523042841_rename_merge_requests_allow_maintainer_to_push.rb
new file mode 100644
index 0000000000000000000000000000000000000000..975bdfe70f45cda5afdd8019e034284acc1e02f5
--- /dev/null
+++ b/db/migrate/20180523042841_rename_merge_requests_allow_maintainer_to_push.rb
@@ -0,0 +1,15 @@
+class RenameMergeRequestsAllowMaintainerToPush < ActiveRecord::Migration
+  include Gitlab::Database::MigrationHelpers
+
+  DOWNTIME = false
+
+  disable_ddl_transaction!
+
+  def up
+    rename_column_concurrently :merge_requests, :allow_maintainer_to_push, :allow_collaboration
+  end
+
+  def down
+    cleanup_concurrent_column_rename :merge_requests, :allow_collaboration, :allow_maintainer_to_push
+  end
+end
diff --git a/db/migrate/20180531220618_change_default_value_for_dsa_key_restriction.rb b/db/migrate/20180531220618_change_default_value_for_dsa_key_restriction.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d0dcacc5b66c00a27530ad3f4eb180bb4f120b83
--- /dev/null
+++ b/db/migrate/20180531220618_change_default_value_for_dsa_key_restriction.rb
@@ -0,0 +1,16 @@
+class ChangeDefaultValueForDsaKeyRestriction < ActiveRecord::Migration
+  # Set this constant to true if this migration requires downtime.
+  DOWNTIME = false
+
+  def up
+    change_column :application_settings, :dsa_key_restriction, :integer, null: false,
+                  default: -1
+
+    execute("UPDATE application_settings SET dsa_key_restriction = -1")
+  end
+
+  def down
+    change_column :application_settings, :dsa_key_restriction, :integer, null: false,
+                  default: 0
+  end
+end
diff --git a/db/post_migrate/20180523125103_cleanup_merge_requests_allow_maintainer_to_push_rename.rb b/db/post_migrate/20180523125103_cleanup_merge_requests_allow_maintainer_to_push_rename.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b9ce4600675a8894af52e0202670a4990d480330
--- /dev/null
+++ b/db/post_migrate/20180523125103_cleanup_merge_requests_allow_maintainer_to_push_rename.rb
@@ -0,0 +1,15 @@
+class CleanupMergeRequestsAllowMaintainerToPushRename < ActiveRecord::Migration
+  include Gitlab::Database::MigrationHelpers
+
+  DOWNTIME = false
+
+  disable_ddl_transaction!
+
+  def up
+    cleanup_concurrent_column_rename :merge_requests, :allow_maintainer_to_push, :allow_collaboration
+  end
+
+  def down
+    rename_column_concurrently :merge_requests, :allow_collaboration, :allow_maintainer_to_push
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 04d3cce5665f8faf5b9b1cac090f47403f88564e..b7d7cd89c14114cfc15e0260f233ac5fd69f3076 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20180530135500) do
+ActiveRecord::Schema.define(version: 20180531220618) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -110,7 +110,7 @@ ActiveRecord::Schema.define(version: 20180530135500) do
     t.text "shared_runners_text_html"
     t.text "after_sign_up_text_html"
     t.integer "rsa_key_restriction", default: 0, null: false
-    t.integer "dsa_key_restriction", default: 0, null: false
+    t.integer "dsa_key_restriction", default: -1, null: false
     t.integer "ecdsa_key_restriction", default: 0, null: false
     t.integer "ed25519_key_restriction", default: 0, null: false
     t.boolean "housekeeping_enabled", default: true, null: false
@@ -1230,7 +1230,7 @@ ActiveRecord::Schema.define(version: 20180530135500) do
     t.boolean "discussion_locked"
     t.integer "latest_merge_request_diff_id"
     t.string "rebase_commit_sha"
-    t.boolean "allow_maintainer_to_push"
+    t.boolean "allow_collaboration"
     t.boolean "squash", default: false, null: false
   end
 
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 62f9884e264c9211a97624b490924fd087360ccd..9f06e20f803d1324ef68e1ac358d17ccdec9c5fb 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -651,7 +651,8 @@ POST /projects/:id/merge_requests
 | `labels`                   | string  | no       | Labels for MR as a comma-separated list                                         |
 | `milestone_id`             | integer | no       | The global ID of a milestone                                                           |
 | `remove_source_branch`     | boolean | no       | Flag indicating if a merge request should remove the source branch when merging |
-| `allow_maintainer_to_push` | boolean | no       | Whether or not a maintainer of the target project can push to the source branch |
+| `allow_collaboration`      | boolean | no       | Allow commits from members who can merge to the target branch                   |
+| `allow_maintainer_to_push` | boolean | no       | Deprecated, see allow_collaboration                                             |
 | `squash`                   | boolean | no       | Squash commits into a single commit when merging                                |
 
 ```json
@@ -709,6 +710,7 @@ POST /projects/:id/merge_requests
   "squash": false,
   "web_url": "http://example.com/example/example/merge_requests/1",
   "discussion_locked": false,
+  "allow_collaboration": false,
   "allow_maintainer_to_push": false,
   "time_stats": {
     "time_estimate": 0,
@@ -741,7 +743,8 @@ PUT /projects/:id/merge_requests/:merge_request_iid
 | `remove_source_branch`     | boolean | no       | Flag indicating if a merge request should remove the source branch when merging |
 | `squash`                   | boolean | no       | Squash commits into a single commit when merging |
 | `discussion_locked`        | boolean | no       | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
-| `allow_maintainer_to_push` | boolean | no       | Whether or not a maintainer of the target project can push to the source branch |
+| `allow_collaboration`      | boolean | no       | Allow commits from members who can merge to the target branch                   |
+| `allow_maintainer_to_push` | boolean | no       | Deprecated, see allow_collaboration                                             |
 
 Must include at least one non-required attribute from above.
 
@@ -799,6 +802,7 @@ Must include at least one non-required attribute from above.
   "squash": false,
   "web_url": "http://example.com/example/example/merge_requests/1",
   "discussion_locked": false,
+  "allow_collaboration": false,
   "allow_maintainer_to_push": false,
   "time_stats": {
     "time_estimate": 0,
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index 5185d843ccb70dcab1eb3d20ed6efab00f1aeb11..9a677bf09b2f0d4d2683352b4809a0e5539ca3c8 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -16,7 +16,7 @@ are very appreciative of the work done by translators and proofreaders!
 - Dutch
 - Esperanto
 - French
-  - Rémy Coutable - [GitLab](https://gitlab.com/rymai), [Crowdin](https://crowdin.com/profile/rymai)
+  - Davy Defaud - [GitLab](https://gitlab.com/DevDef), [Crowdin](https://crowdin.com/profile/DevDef)
 - German
 - Indonesian
   - Ahmad Naufal Mukhtar - [GitLab](https://gitlab.com/anaufalm), [Crowdin](https://crowdin.com/profile/anaufalm)
diff --git a/doc/user/project/merge_requests/allow_collaboration.md b/doc/user/project/merge_requests/allow_collaboration.md
new file mode 100644
index 0000000000000000000000000000000000000000..859ac92ef890747ba90cf5ef10f682492cac656e
--- /dev/null
+++ b/doc/user/project/merge_requests/allow_collaboration.md
@@ -0,0 +1,20 @@
+# Allow collaboration on merge requests across forks
+
+> [Introduced][ce-17395] in GitLab 10.6.
+
+This feature is available for merge requests across forked projects that are
+publicly accessible. It makes it easier for members of projects to
+collaborate on merge requests across forks.
+
+When enabled for a merge request, members with merge access to the target
+branch of the project will be granted write permissions to the source branch
+of the merge request.
+
+The feature can only be enabled by users who already have push access to the
+source project, and only lasts while the merge request is open.
+
+Enable this functionality while creating or editing a merge request:
+
+![Enable collaboration](./img/allow_collaboration.png)
+
+[ce-17395]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17395
diff --git a/doc/user/project/merge_requests/img/allow_collaboration.png b/doc/user/project/merge_requests/img/allow_collaboration.png
new file mode 100644
index 0000000000000000000000000000000000000000..75596e7d9adfae4eea09d60febffa798ae17c5d2
Binary files /dev/null and b/doc/user/project/merge_requests/img/allow_collaboration.png differ
diff --git a/doc/user/project/merge_requests/img/allow_maintainer_push.png b/doc/user/project/merge_requests/img/allow_maintainer_push.png
deleted file mode 100644
index 91cc399f4ff62770e23253d053a593f35716f041..0000000000000000000000000000000000000000
Binary files a/doc/user/project/merge_requests/img/allow_maintainer_push.png and /dev/null differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index b75bcacc9d7cbfde907dfb1fdbc59ba45afd4281..50979e820973af1e85341585c4d6a32ba1af640c 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -28,7 +28,7 @@ With GitLab merge requests, you can:
 - Enable [fast-forward merge requests](#fast-forward-merge-requests)
 - Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch
 - [Create new merge requests by email](#create-new-merge-requests-by-email)
-- Allow maintainers of the target project to push directly to the fork by [allowing edits from maintainers](maintainer_access.md)
+- [Allow collaboration](allow_collaboration.md) so members of the target project can push directly to the fork
 - [Squash and merge](squash_and_merge.md) for a cleaner commit history
 
 With **[GitLab Enterprise Edition][ee]**, you can also:
diff --git a/doc/user/project/merge_requests/maintainer_access.md b/doc/user/project/merge_requests/maintainer_access.md
index 89f71e16a50bdcdbc11c62eccab3481d74678c14..d59afecd375c9b81faf2cc355671ffd3c5ff66b8 100644
--- a/doc/user/project/merge_requests/maintainer_access.md
+++ b/doc/user/project/merge_requests/maintainer_access.md
@@ -1,20 +1 @@
-# Allow maintainer pushes for merge requests across forks
-
-> [Introduced][ce-17395] in GitLab 10.6.
-
-This feature is available for merge requests across forked projects that are
-publicly accessible. It makes it easier for maintainers of projects to
-collaborate on merge requests across forks.
-
-When enabled for a merge request, members with merge access to the target
-branch of the project will be granted write permissions to the source branch
-of the merge request.
-
-The feature can only be enabled by users who already have push access to the
-source project, and only lasts while the merge request is open.
-
-Enable this functionality while creating a merge request:
-
-![Enable maintainer edits](./img/allow_maintainer_push.png)
-
-[ce-17395]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17395
+This document was moved to [another location](allow_collaboration.md).
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index c4537036a3a96c0c7cc7863d9d10bd595105112f..c76d3ff45d061ffeaf8c1e146e47b56fe33a8468 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -559,7 +559,9 @@ module API
       expose :discussion_locked
       expose :should_remove_source_branch?, as: :should_remove_source_branch
       expose :force_remove_source_branch?, as: :force_remove_source_branch
-      expose :allow_maintainer_to_push, if: -> (merge_request, _) { merge_request.for_fork? }
+      expose :allow_collaboration, if: -> (merge_request, _) { merge_request.for_fork? }
+      # Deprecated
+      expose :allow_collaboration, as: :allow_maintainer_to_push, if: -> (merge_request, _) { merge_request.for_fork? }
 
       expose :web_url do |merge_request, options|
         Gitlab::UrlBuilder.build(merge_request)
diff --git a/lib/api/events.rb b/lib/api/events.rb
index b0713ff1d54b45594842f23201188e711e19ce0a..fc4ba5a31888125e9e0124ad057df220024cd44a 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -17,6 +17,7 @@ module API
 
       def present_events(events)
         events = events.reorder(created_at: params[:sort])
+                 .with_associations
 
         present paginate(events), with: Entities::Event
       end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 278d53427f0ac0b9723107aaf4ccd889e37be6c4..af7d2471b3431cc2ac5a23b401e09e2925dc6c7f 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -162,7 +162,8 @@ module API
           optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
           optional :labels, type: String, desc: 'Comma-separated list of label names'
           optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging'
-          optional :allow_maintainer_to_push, type: Boolean, desc: 'Whether a maintainer of the target project can push to the source project'
+          optional :allow_collaboration, type: Boolean, desc: 'Allow commits from members who can merge to the target branch'
+          optional :allow_maintainer_to_push, type: Boolean, as: :allow_collaboration, desc: '[deprecated] See allow_collaboration'
           optional :squash, type: Grape::API::Boolean, desc: 'When true, the commits will be squashed into a single commit on merge'
 
           use :optional_params_ee
diff --git a/lib/backup.rb b/lib/backup.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e2c62af23aefc7a4084fe7ea69de809dd4260b5a
--- /dev/null
+++ b/lib/backup.rb
@@ -0,0 +1,3 @@
+module Backup
+  Error = Class.new(StandardError)
+end
diff --git a/lib/backup/database.rb b/lib/backup/database.rb
index 1608f7ad02db73d7d97a855ea251e4119e8ba346..086ca5986bd83be4c31561eb1f8c2c04f0e37452 100644
--- a/lib/backup/database.rb
+++ b/lib/backup/database.rb
@@ -44,7 +44,7 @@ module Backup
       end
 
       report_success(success)
-      abort 'Backup failed' unless success
+      raise Backup::Error, 'Backup failed' unless success
     end
 
     def restore
@@ -72,7 +72,7 @@ module Backup
       end
 
       report_success(success)
-      abort 'Restore failed' unless success
+      abort Backup::Error, 'Restore failed' unless success
     end
 
     protected
diff --git a/lib/backup/files.rb b/lib/backup/files.rb
index 9895db9e451e5b9ca0888feccd657c9db1a05ab4..d769a3ee7b042e1189a8b363e5715606b365acd6 100644
--- a/lib/backup/files.rb
+++ b/lib/backup/files.rb
@@ -26,7 +26,7 @@ module Backup
 
         unless status.zero?
           puts output
-          abort 'Backup failed'
+          raise Backup::Error, 'Backup failed'
         end
 
         run_pipeline!([%W(tar --exclude=lost+found -C #{@backup_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600])
@@ -39,7 +39,11 @@ module Backup
     def restore
       backup_existing_files_dir
 
-      run_pipeline!([%w(gzip -cd), %W(tar --unlink-first --recursive-unlink -C #{app_files_dir} -xf -)], in: backup_tarball)
+      run_pipeline!([%w(gzip -cd), %W(#{tar} --unlink-first --recursive-unlink -C #{app_files_dir} -xf -)], in: backup_tarball)
+    end
+
+    def tar
+      system(*%w[gtar --version], out: '/dev/null') ? 'gtar' : 'tar'
     end
 
     def backup_existing_files_dir
@@ -61,7 +65,7 @@ module Backup
 
     def run_pipeline!(cmd_list, options = {})
       status_list = Open3.pipeline(*cmd_list, options)
-      abort 'Backup failed' unless status_list.compact.all?(&:success?)
+      raise Backup::Error, 'Backup failed' unless status_list.compact.all?(&:success?)
     end
   end
 end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index a8da0c7edeffc1fbe2413d99e981a701be07db9c..a3641505196919caeea0beb69a81d8ed1c4df2ca 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -27,7 +27,7 @@ module Backup
           progress.puts "done".color(:green)
         else
           puts "creating archive #{tar_file} failed".color(:red)
-          abort 'Backup failed'
+          raise Backup::Error, 'Backup failed'
         end
 
         upload
@@ -52,7 +52,7 @@ module Backup
         progress.puts "done".color(:green)
       else
         puts "uploading backup to #{remote_directory} failed".color(:red)
-        abort 'Backup failed'
+        raise Backup::Error, 'Backup failed'
       end
     end
 
@@ -66,7 +66,7 @@ module Backup
           progress.puts "done".color(:green)
         else
           puts "deleting tmp directory '#{dir}' failed".color(:red)
-          abort 'Backup failed'
+          raise Backup::Error, 'Backup failed'
         end
       end
     end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 84670d6582ecde5eb40da6cf1ea2b4f6ddb10845..1b1c83d9fb38287ced18f14f583bb61c1fee6ee6 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -17,7 +17,10 @@ module Backup
 
       Project.find_each(batch_size: 1000) do |project|
         progress.print " * #{display_repo_path(project)} ... "
-        path_to_project_repo = path_to_repo(project)
+
+        path_to_project_repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          path_to_repo(project)
+        end
         path_to_project_bundle = path_to_bundle(project)
 
         # Create namespace dir or hashed path if missing
@@ -51,7 +54,9 @@ module Backup
         end
 
         wiki = ProjectWiki.new(project)
-        path_to_wiki_repo = path_to_repo(wiki)
+        path_to_wiki_repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          path_to_repo(wiki)
+        end
         path_to_wiki_bundle = path_to_bundle(wiki)
 
         if File.exist?(path_to_wiki_repo)
@@ -111,7 +116,9 @@ module Backup
       # TODO: Need to find a way to do this for gitaly
       # Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/1195
       in_path(path_to_tars(project)) do |dir|
-        path_to_project_repo = path_to_repo(project)
+        path_to_project_repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          path_to_repo(project)
+        end
         cmd = %W(tar -xf #{path_to_tars(project, dir)} -C #{path_to_project_repo} #{dir})
 
         output, status = Gitlab::Popen.popen(cmd)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 7acf11e3c91cf26335a576e8a54dbc7ee7fcf71a..bbbe0111a6f5281994b07a8b48c9e0ec78f669df 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -109,7 +109,7 @@ module Gitlab
       end
 
       def ==(other)
-        path == other.path
+        [storage, relative_path] == [other.storage, other.relative_path]
       end
 
       def path
diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb
index 695462c7dd2ad5c7878501a289614a9aa8ccc322..0c224bd1971c9deebbff49d731bb61ae7b5eef13 100644
--- a/lib/gitlab/import_export/repo_saver.rb
+++ b/lib/gitlab/import_export/repo_saver.rb
@@ -26,10 +26,6 @@ module Gitlab
         @shared.error(e)
         false
       end
-
-      def path_to_repo
-        @project.repository.path_to_repo
-      end
     end
   end
 end
diff --git a/lib/gitlab/import_export/wiki_repo_saver.rb b/lib/gitlab/import_export/wiki_repo_saver.rb
index 5fa2e101e29506834ae3aa6c53c98682658a9838..2fd62c0fc7b1f444fac84724bbb40e65dc79dede 100644
--- a/lib/gitlab/import_export/wiki_repo_saver.rb
+++ b/lib/gitlab/import_export/wiki_repo_saver.rb
@@ -22,12 +22,8 @@ module Gitlab
         "project.wiki.bundle"
       end
 
-      def path_to_repo
-        @wiki.repository.path_to_repo
-      end
-
       def wiki_repository_exists?
-        File.exist?(@wiki.repository.path_to_repo) && !@wiki.repository.empty?
+        @wiki.repository.exists? && !@wiki.repository.empty?
       end
     end
   end
diff --git a/lib/gitlab/task_helpers.rb b/lib/gitlab/task_helpers.rb
index 42be301fd9b38ef4b3c62e2aa91f1e27a4a0e429..723e655c15015bd4931a2942283baa345428897a 100644
--- a/lib/gitlab/task_helpers.rb
+++ b/lib/gitlab/task_helpers.rb
@@ -128,10 +128,12 @@ module Gitlab
     end
 
     def all_repos
-      Gitlab.config.repositories.storages.each_value do |repository_storage|
-        IO.popen(%W(find #{repository_storage.legacy_disk_path} -mindepth 2 -type d -name *.git)) do |find|
-          find.each_line do |path|
-            yield path.chomp
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.each_value do |repository_storage|
+          IO.popen(%W(find #{repository_storage.legacy_disk_path} -mindepth 2 -type d -name *.git)) do |find|
+            find.each_line do |path|
+              yield path.chomp
+            end
           end
         end
       end
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 8cf5d636743260bdcca5f0dc052b702651d86363..27560abfb966a05d576d18249162f18516d58e8c 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -65,7 +65,7 @@ module Gitlab
       return false unless can_access_git?
       return false unless project
 
-      return false if !user.can?(:push_code, project) && !project.branch_allows_maintainer_push?(user, ref)
+      return false if !user.can?(:push_code, project) && !project.branch_allows_collaboration?(user, ref)
 
       if protected?(ProtectedBranch, project, ref)
         protected_branch_accessible_to?(ref, action: :push)
diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake
index d6d152854899c4b33edad624b794b46f5fb94e41..52ae1330d7f2e1270447244040720bcb9f6da6b5 100644
--- a/lib/tasks/gitlab/cleanup.rake
+++ b/lib/tasks/gitlab/cleanup.rake
@@ -12,7 +12,7 @@ namespace :gitlab do
       namespaces  = Namespace.pluck(:path)
       namespaces << HASHED_REPOSITORY_NAME  # add so that it will be ignored
       Gitlab.config.repositories.storages.each do |name, repository_storage|
-        git_base_path = repository_storage.legacy_disk_path
+        git_base_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository_storage.legacy_disk_path }
         all_dirs = Dir.glob(git_base_path + '/*')
 
         puts git_base_path.color(:yellow)
@@ -54,7 +54,8 @@ namespace :gitlab do
 
       move_suffix = "+orphaned+#{Time.now.to_i}"
       Gitlab.config.repositories.storages.each do |name, repository_storage|
-        repo_root = repository_storage.legacy_disk_path
+        repo_root = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository_storage.legacy_disk_path }
+
         # Look for global repos (legacy, depth 1) and normal repos (depth 2)
         IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find|
           find.each_line do |path|
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 035a2275d9fbdb68cbf358ae1745c0cca071c4c4..8ae04cd2f8844c12a36e1e6648dde843a13cf707 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -331,7 +331,7 @@ msgstr ""
 msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
 msgstr ""
 
-msgid "Allow edits from maintainers."
+msgid "Allow commits from members who can merge to the target branch."
 msgstr ""
 
 msgid "Allow rendering of PlantUML diagrams in Asciidoc documents."
@@ -4894,7 +4894,7 @@ msgstr ""
 msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
 msgstr ""
 
-msgid "mrWidget|Allows edits from maintainers"
+msgid "mrWidget|Allows commits from members who can merge to the target branch"
 msgstr ""
 
 msgid "mrWidget|Cancel automatic merge"
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index b048da1991ce09b0ad897344c877f2b816d861bb..683c57c96f8a6e7180a6ba51188a3edd4aed11d2 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -477,4 +477,28 @@ describe ApplicationController do
       end
     end
   end
+
+  describe '#access_denied' do
+    controller(described_class) do
+      def index
+        access_denied!(params[:message])
+      end
+    end
+
+    before do
+      sign_in user
+    end
+
+    it 'renders a 404 without a message' do
+      get :index
+
+      expect(response).to have_gitlab_http_status(404)
+    end
+
+    it 'renders a 403 when a message is passed to access denied' do
+      get :index, message: 'None shall pass'
+
+      expect(response).to have_gitlab_http_status(403)
+    end
+  end
 end
diff --git a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
index 27f558e1b5da2d27a9fbe13da22960eee9a18d6c..d20471ef603f57f802758bb9f925a3fb60fe8223 100644
--- a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
+++ b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
@@ -43,13 +43,13 @@ describe ControllerWithCrossProjectAccessCheck do
         end
       end
 
-      it 'renders a 404 with trying to access a cross project page' do
+      it 'renders a 403 with trying to access a cross project page' do
         message = "This page is unavailable because you are not allowed to read "\
                   "information across multiple projects."
 
         get :index
 
-        expect(response).to have_gitlab_http_status(404)
+        expect(response).to have_gitlab_http_status(403)
         expect(response.body).to match(/#{message}/)
       end
 
@@ -119,7 +119,7 @@ describe ControllerWithCrossProjectAccessCheck do
 
         get :index
 
-        expect(response).to have_gitlab_http_status(404)
+        expect(response).to have_gitlab_http_status(403)
       end
 
       it 'is executed when the `unless` condition returns true' do
@@ -127,19 +127,19 @@ describe ControllerWithCrossProjectAccessCheck do
 
         get :index
 
-        expect(response).to have_gitlab_http_status(404)
+        expect(response).to have_gitlab_http_status(403)
       end
 
       it 'does not skip the check on an action that is not skipped' do
         get :show, id: 'hello'
 
-        expect(response).to have_gitlab_http_status(404)
+        expect(response).to have_gitlab_http_status(403)
       end
 
       it 'does not skip the check on an action that was not defined to skip' do
         get :edit, id: 'hello'
 
-        expect(response).to have_gitlab_http_status(404)
+        expect(response).to have_gitlab_http_status(403)
       end
     end
   end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 30c06ddf7440a51495998838a84c231bfa9c7547..416a09e168420b2aa2b5a4a494027e884c7195ea 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -32,7 +32,7 @@ describe SearchController do
     it 'still blocks searches without a project_id' do
       get :show, search: 'hello'
 
-      expect(response).to have_gitlab_http_status(404)
+      expect(response).to have_gitlab_http_status(403)
     end
 
     it 'allows searches with a project_id' do
diff --git a/spec/controllers/users/terms_controller_spec.rb b/spec/controllers/users/terms_controller_spec.rb
index a744463413cf3134558e4c7af637794b316f77bc..0d77e91a67d07f0847e5bb28e3d3dcb41f4d8a53 100644
--- a/spec/controllers/users/terms_controller_spec.rb
+++ b/spec/controllers/users/terms_controller_spec.rb
@@ -1,6 +1,7 @@
 require 'spec_helper'
 
 describe Users::TermsController do
+  include TermsHelper
   let(:user) { create(:user) }
   let(:term) { create(:term) }
 
@@ -15,10 +16,25 @@ describe Users::TermsController do
       expect(response).to have_gitlab_http_status(:redirect)
     end
 
-    it 'shows terms when they exist' do
-      term
+    context 'when terms exist' do
+      before do
+        stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+        term
+      end
+
+      it 'shows terms when they exist' do
+        get :index
+
+        expect(response).to have_gitlab_http_status(:success)
+      end
 
-      expect(response).to have_gitlab_http_status(:success)
+      it 'shows a message when the user already accepted the terms' do
+        accept_terms(user)
+
+        get :index
+
+        expect(controller).to set_flash.now[:notice].to(/already accepted/)
+      end
     end
   end
 
diff --git a/spec/factories/term_agreements.rb b/spec/factories/term_agreements.rb
index 557599e663d2996542c72bd678e37dc12218fce3..3c4eebd0196810a2b6b09d43c77c7c98f2d78b7c 100644
--- a/spec/factories/term_agreements.rb
+++ b/spec/factories/term_agreements.rb
@@ -3,4 +3,12 @@ FactoryBot.define do
     term
     user
   end
+
+  trait :declined do
+    accepted false
+  end
+
+  trait :accepted do
+    accepted true
+  end
 end
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
index a3323da1b1f210aafeb57cbd46de8f8b34721895..1808d0c0a0c044745e821b15c5e91f31536a51e4 100644
--- a/spec/features/merge_request/maintainer_edits_fork_spec.rb
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -14,7 +14,7 @@ describe 'a maintainer edits files on a source-branch of an MR from a fork', :js
            source_branch: 'fix',
            target_branch: 'master',
            author: author,
-           allow_maintainer_to_push: true)
+           allow_collaboration: true)
   end
 
   before do
diff --git a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb
similarity index 70%
rename from spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
rename to spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb
index eb41d7de8edcaa63882ef207f5d0107ea70cc182..0af37d7653999ef291188ba5b91eb215151f4e0a 100644
--- a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
+++ b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe 'create a merge request that allows maintainers to push', :js do
+describe 'create a merge request, allowing commits from members who can merge to the target branch', :js do
   include ProjectForksHelper
   let(:user) { create(:user) }
   let(:target_project) { create(:project, :public, :repository) }
@@ -21,16 +21,16 @@ describe 'create a merge request that allows maintainers to push', :js do
     sign_in(user)
   end
 
-  it 'allows setting maintainer push possible' do
+  it 'allows setting possible' do
     visit_new_merge_request
 
-    check 'Allow edits from maintainers'
+    check 'Allow commits from members who can merge to the target branch'
 
     click_button 'Submit merge request'
 
     wait_for_requests
 
-    expect(page).to have_content('Allows edits from maintainers')
+    expect(page).to have_content('Allows commits from members who can merge to the target branch')
   end
 
   it 'shows a message when one of the projects is private' do
@@ -57,12 +57,12 @@ describe 'create a merge request that allows maintainers to push', :js do
 
       visit_new_merge_request
 
-      expect(page).not_to have_content('Allows edits from maintainers')
+      expect(page).not_to have_content('Allows commits from members who can merge to the target branch')
     end
   end
 
-  context 'when a maintainer tries to edit the option' do
-    let(:maintainer) { create(:user) }
+  context 'when a member who can merge tries to edit the option' do
+    let(:member) { create(:user) }
     let(:merge_request) do
       create(:merge_request,
              source_project: source_project,
@@ -71,15 +71,15 @@ describe 'create a merge request that allows maintainers to push', :js do
     end
 
     before do
-      target_project.add_master(maintainer)
+      target_project.add_master(member)
 
-      sign_in(maintainer)
+      sign_in(member)
     end
 
-    it 'it hides the option from maintainers' do
+    it 'it hides the option from members' do
       visit edit_project_merge_request_path(target_project, merge_request)
 
-      expect(page).not_to have_content('Allows edits from maintainers')
+      expect(page).not_to have_content('Allows commits from members who can merge to the target branch')
     end
   end
 end
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index 60fe30bd898821996d84c4f7a66d0991d98c4d16..d0912e645bc1db600d4e21cedc3a350e39da1d57 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -87,11 +87,13 @@ feature 'Import/Export - project import integration test', :js do
 
   def wiki_exists?(project)
     wiki = ProjectWiki.new(project)
-    File.exist?(wiki.repository.path_to_repo) && !wiki.repository.empty?
+    wiki.repository.exists? && !wiki.repository.empty?
   end
 
   def project_hook_exists?(project)
-    Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository).exists?
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository).exists?
+    end
   end
 
   def click_import_project_tab
diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb
index 1efa5cd549067de0b67b92eb9c7c2be13998c09d..af407c52917dc8de9cf4e0cea0bad2baeae2eeaf 100644
--- a/spec/features/users/terms_spec.rb
+++ b/spec/features/users/terms_spec.rb
@@ -39,6 +39,22 @@ describe 'Users > Terms' do
     end
   end
 
+  context 'when the user has already accepted the terms' do
+    before do
+      accept_terms(user)
+    end
+
+    it 'allows the user to continue to the app' do
+      visit terms_path
+
+      expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}"
+
+      click_link 'Continue'
+
+      expect(current_path).to eq(root_path)
+    end
+  end
+
   context 'terms were enforced while session is active', :js do
     let(:project) { create(:project) }
 
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index 46031961ccafe8bc3f937093673269dd6714e9a7..f7bc137c90cadf1f8a3ab4e87391cbe03317e084 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -13,6 +13,7 @@
     "assignee_id": { "type": ["integer", "null"] },
     "subscribed": { "type": ["boolean", "null"] },
     "participants": { "type": "array" },
+    "allow_collaboration": { "type": "boolean"},
     "allow_maintainer_to_push": { "type": "boolean"}
   },
   "additionalProperties": false
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 7be8c9e3e67bd4093c5b7dabc80b62547a18c668..ee5588fa6c6f7c6794a66dacab1f33b4fe00bd95 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -31,7 +31,7 @@
     "source_project_id": { "type": "integer" },
     "target_branch": { "type": "string" },
     "target_project_id": { "type": "integer" },
-    "allow_maintainer_to_push": { "type": "boolean"},
+    "allow_collaboration": { "type": "boolean"},
     "metrics": {
       "oneOf": [
         { "type": "null" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
index f97461ce9ccb52b23af99adea8c87b45893dcaf1..f7adc4e0b914d3e28d2f614bea1f1ee04b7d28ac 100644
--- a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
+++ b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
@@ -82,6 +82,7 @@
         "human_time_estimate": { "type": ["string", "null"] },
         "human_total_time_spent": { "type": ["string", "null"] }
       },
+      "allow_collaboration": { "type": ["boolean", "null"] },
       "allow_maintainer_to_push": { "type": ["boolean", "null"] }
     },
     "required": [
diff --git a/spec/initializers/fog_google_https_private_urls_spec.rb b/spec/initializers/fog_google_https_private_urls_spec.rb
index de3c157ab7bd72b45f48d295ff1bfd9ea350138b..08346b71feecc9915c241ce9ac119e8a4bd56950 100644
--- a/spec/initializers/fog_google_https_private_urls_spec.rb
+++ b/spec/initializers/fog_google_https_private_urls_spec.rb
@@ -1,13 +1,13 @@
 require 'spec_helper'
 
-describe 'Fog::Storage::GoogleXML::File' do
+describe 'Fog::Storage::GoogleXML::File', :fog_requests do
   let(:storage) do
     Fog.mock!
-    Fog::Storage.new({
-                       google_storage_access_key_id: "asdf",
-                       google_storage_secret_access_key: "asdf",
-                       provider: "Google"
-                     })
+    Fog::Storage.new(
+      google_storage_access_key_id: "asdf",
+      google_storage_secret_access_key: "asdf",
+      provider: "Google"
+    )
   end
 
   let(:file) do
diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js
index c63f15e5880ce2a0e8159af55929c8a6a62b4f23..c36b607a34e93a246d8151b8eb0b1c3e094e6ac5 100644
--- a/spec/javascripts/vue_shared/components/table_pagination_spec.js
+++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js
@@ -51,7 +51,7 @@ describe('Pagination component', () => {
 
         expect(
           component.$el.querySelector('.js-previous-button').classList.contains('disabled'),
-          ).toEqual(true);
+        ).toEqual(true);
 
         component.$el.querySelector('.js-previous-button a').click();
 
diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb
index 99872211a4e0a7d954732d5b817c7bdc228d9d6d..63f2298357f30e4250c72e70ae91eaefd227d732 100644
--- a/spec/lib/backup/files_spec.rb
+++ b/spec/lib/backup/files_spec.rb
@@ -46,7 +46,9 @@ describe Backup::Files do
       end
 
       it 'calls tar command with unlink' do
-        expect(subject).to receive(:run_pipeline!).with([%w(gzip -cd), %w(tar --unlink-first --recursive-unlink -C /var/gitlab-registry -xf -)], any_args)
+        expect(subject).to receive(:tar).and_return('blabla-tar')
+
+        expect(subject).to receive(:run_pipeline!).with([%w(gzip -cd), %w(blabla-tar --unlink-first --recursive-unlink -C /var/gitlab-registry -xf -)], any_args)
         subject.restore
       end
     end
diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb
index 23c04a1a1013e21cd3d5c9fd70630330c2863f8d..ca319679e80ba9b7059570e4c00161d18f9ca543 100644
--- a/spec/lib/backup/manager_spec.rb
+++ b/spec/lib/backup/manager_spec.rb
@@ -274,16 +274,13 @@ describe Backup::Manager do
         }
       )
 
-      # the Fog mock only knows about directories we create explicitly
       Fog.mock!
+
+      # the Fog mock only knows about directories we create explicitly
       connection = ::Fog::Storage.new(Gitlab.config.backup.upload.connection.symbolize_keys)
       connection.directories.create(key: Gitlab.config.backup.upload.remote_directory)
     end
 
-    after do
-      Fog.unmock!
-    end
-
     context 'target path' do
       it 'uses the tar filename by default' do
         expect_any_instance_of(Fog::Collection).to receive(:create)
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index f583b2021a296e7e44dff23ad1d3ea61408cabb3..92a27e308d2758ee3f6694ed51b2e374b55a5b30 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -34,7 +34,9 @@ describe Backup::Repository do
     let(:timestamp) { Time.utc(2017, 3, 22) }
     let(:temp_dirs) do
       Gitlab.config.repositories.storages.map do |name, storage|
-        File.join(storage.legacy_disk_path, '..', 'repositories.old.' + timestamp.to_i.to_s)
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          File.join(storage.legacy_disk_path, '..', 'repositories.old.' + timestamp.to_i.to_s)
+        end
       end
     end
 
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 5c8a19a53bc291436df2377fb00404a3fd7baf49..468f6ff6d24498e073984fe60cb2dd9ec71d2397 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -20,6 +20,13 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
     Rainbow.enabled = @rainbow
   end
 
+  around do |example|
+    # TODO migrate BareRepositoryImport https://gitlab.com/gitlab-org/gitaly/issues/953
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      example.run
+    end
+  end
+
   shared_examples 'importing a repository' do
     describe '.execute' do
       it 'creates a project for a repository in storage' do
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 1504826c7a57b47a4280d8bf953666362ff069e1..afd8f5da39ff075753b6252264c9516be2663970 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -62,8 +62,10 @@ describe ::Gitlab::BareRepositoryImport::Repository do
 
     before do
       gitlab_shell.create_repository(repository_storage, hashed_path)
-      repository = Rugged::Repository.new(repo_path)
-      repository.config['gitlab.fullpath'] = 'to/repo'
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        repository = Rugged::Repository.new(repo_path)
+        repository.config['gitlab.fullpath'] = 'to/repo'
+      end
     end
 
     after do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 20b0b2c53a0a6a785d5b7362f963766194219434..8dd7911f49ccefb00a26f01d5f82d547345055a2 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -159,6 +159,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
     let(:feature2) { 'feature2' }
 
     around do |example|
+      # discover_default_branch will be moved to gitaly-ruby
       Gitlab::GitalyClient::StorageSettings.allow_disk_access do
         example.run
       end
@@ -373,6 +374,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
 
   context '#submodules' do
     around do |example|
+      # TODO #submodules will be removed, has been migrated to gitaly
       Gitlab::GitalyClient::StorageSettings.allow_disk_access do
         example.run
       end
@@ -1055,6 +1057,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
 
   describe "#rugged_commits_between" do
     around do |example|
+      # TODO #rugged_commits_between will be removed, has been migrated to gitaly
       Gitlab::GitalyClient::StorageSettings.allow_disk_access do
         example.run
       end
@@ -1703,6 +1706,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
     let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] }
 
     around do |example|
+      # TODO #batch_existence isn't used anywhere, can we remove it?
       Gitlab::GitalyClient::StorageSettings.allow_disk_access do
         example.run
       end
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
index 32ec1e029c855f7b4230676f46c03cb29205ac86..95dc47e2a007a8fdb49cbc1817741cd446e316de 100644
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ b/spec/lib/gitlab/git/rev_list_spec.rb
@@ -9,9 +9,11 @@ describe Gitlab::Git::RevList do
   end
 
   def stub_popen_rev_list(*additional_args, with_lazy_block: true, output:)
+    repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.path }
+
     params = [
       args_for_popen(additional_args),
-      repository.path,
+      repo_path,
       {},
       hash_including(lazy_block: with_lazy_block ? anything : nil)
     ]
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index dfffea7797f10c9d6c285d11621cd9d82fa6324d..0d5f6a0b576d5f4c9e45fce66141ac104ec8df53 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -552,7 +552,7 @@ describe Gitlab::GitAccess do
       it 'returns not found' do
         project.add_guest(user)
         repo = project.repository
-        FileUtils.rm_rf(repo.path)
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access { FileUtils.rm_rf(repo.path) }
 
         # Sanity check for rm_rf
         expect(repo.exists?).to eq(false)
@@ -750,20 +750,22 @@ describe Gitlab::GitAccess do
 
     def merge_into_protected_branch
       @protected_branch_merge_commit ||= begin
-        stub_git_hooks
-        project.repository.add_branch(user, unprotected_branch, 'feature')
-        target_branch = project.repository.lookup('feature')
-        source_branch = project.repository.create_file(
-          user,
-          'filename',
-          'This is the file content',
-          message: 'This is a good commit message',
-          branch_name: unprotected_branch)
-        rugged = project.repository.rugged
-        author = { email: "email@example.com", time: Time.now, name: "Example Git User" }
-
-        merge_index = rugged.merge_commits(target_branch, source_branch)
-        Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged))
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          stub_git_hooks
+          project.repository.add_branch(user, unprotected_branch, 'feature')
+          target_branch = project.repository.lookup('feature')
+          source_branch = project.repository.create_file(
+            user,
+            'filename',
+            'This is the file content',
+            message: 'This is a good commit message',
+            branch_name: unprotected_branch)
+          rugged = project.repository.rugged
+          author = { email: "email@example.com", time: Time.now, name: "Example Git User" }
+
+          merge_index = rugged.merge_commits(target_branch, source_branch)
+          Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged))
+        end
       end
     end
 
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index 17e06a6a83f3e6a1ccc3a58ee85dfcd1ef9e5dd8..71fd5a51c3b510e54d0920a70f673920d5c51317 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -41,8 +41,10 @@ describe 'forked project import' do
 
   after do
     FileUtils.rm_rf(export_path)
-    FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
-    FileUtils.rm_rf(project.repository.path_to_repo)
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
+      FileUtils.rm_rf(project.repository.path_to_repo)
+    end
   end
 
   it 'can access the MR' do
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index dc806d036ff5b11aa5daaccec32c291cfcbd0806..013b8895f67c7f52f5991cf6f00e58af606ce32f 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -23,8 +23,10 @@ describe Gitlab::ImportExport::RepoRestorer do
 
     after do
       FileUtils.rm_rf(export_path)
-      FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
-      FileUtils.rm_rf(project.repository.path_to_repo)
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
+        FileUtils.rm_rf(project.repository.path_to_repo)
+      end
     end
 
     it 'restores the repo successfully' do
@@ -34,7 +36,9 @@ describe Gitlab::ImportExport::RepoRestorer do
     it 'has the webhooks' do
       restorer.restore
 
-      expect(Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository)).to exist
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        expect(Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository)).to exist
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 2aebdc57f7cd5d73143dc3ce23d5a0cac0dc42f2..5b289ceb3b2cc8f914297d9ee915fcfa9be96cd3 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -170,7 +170,7 @@ MergeRequest:
 - last_edited_by_id
 - head_pipeline_id
 - discussion_locked
-- allow_maintainer_to_push
+- allow_collaboration
 MergeRequestDiff:
 - id
 - state
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index bf6ee4b0b59967b89f0a4abbca097ab55f6c8743..14eae22a2ec0be4dd9235c7623e1a38bb77916cd 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -405,7 +405,11 @@ describe Gitlab::Shell do
     describe '#create_repository' do
       shared_examples '#create_repository' do
         let(:repository_storage) { 'default' }
-        let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage].legacy_disk_path }
+        let(:repository_storage_path) do
+          Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            Gitlab.config.repositories.storages[repository_storage].legacy_disk_path
+          end
+        end
         let(:repo_name) { 'project/path' }
         let(:created_path) { File.join(repository_storage_path, repo_name + '.git') }
 
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 97b6069f64dfd97431794d3accba9002fad509df..0469d984a4072a553ad2f68f73953b4e33ec0fc4 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -142,7 +142,7 @@ describe Gitlab::UserAccess do
           target_project: canonical_project,
           source_project: project,
           source_branch: 'awesome-feature',
-          allow_maintainer_to_push: true
+          allow_collaboration: true
         )
       end
 
diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb
index 5187821e8f423e32eb55a62a63749ad69c1eb163..e0569218d78f4f129270e3455f1774d93d0e8023 100644
--- a/spec/lib/object_storage/direct_upload_spec.rb
+++ b/spec/lib/object_storage/direct_upload_spec.rb
@@ -17,6 +17,10 @@ describe ObjectStorage::DirectUpload do
 
   let(:direct_upload) { described_class.new(credentials, bucket_name, object_name, has_length: has_length, maximum_size: maximum_size) }
 
+  before do
+    Fog.unmock!
+  end
+
   describe '#has_length' do
     context 'is known' do
       let(:has_length) { true }
diff --git a/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb b/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7e61ab9b52ea9511a0108023e7918256b195d8cd
--- /dev/null
+++ b/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20180531220618_change_default_value_for_dsa_key_restriction.rb')
+
+describe ChangeDefaultValueForDsaKeyRestriction, :migration do
+  let(:application_settings) { table(:application_settings) }
+
+  before do
+    application_settings.create!
+  end
+
+  it 'changes the default value for dsa_key_restriction' do
+    expect(application_settings.first.dsa_key_restriction).to eq(0)
+
+    migrate!
+
+    application_settings.reset_column_information
+    new_setting = application_settings.create!
+
+    expect(application_settings.count).to eq(2)
+    expect(new_setting.dsa_key_restriction).to eq(-1)
+  end
+
+  it 'changes the existing setting' do
+    setting = application_settings.last
+
+    expect(setting.dsa_key_restriction).to eq(0)
+
+    migrate!
+
+    expect(application_settings.count).to eq(1)
+    expect(setting.reload.dsa_key_restriction).to eq(-1)
+  end
+end
diff --git a/spec/models/application_setting/term_spec.rb b/spec/models/application_setting/term_spec.rb
index 1eddf3c56ff563af200ddea4bfca6158807487ef..aa49594f4d12dcb01f5966eaffe7f5f7da30f214 100644
--- a/spec/models/application_setting/term_spec.rb
+++ b/spec/models/application_setting/term_spec.rb
@@ -12,4 +12,41 @@ describe ApplicationSetting::Term do
       expect(described_class.latest).to eq(terms)
     end
   end
+
+  describe '#accepted_by_user?' do
+    let(:user) { create(:user) }
+    let(:term) { create(:term) }
+
+    it 'is true when the user accepted the terms' do
+      accept_terms(term, user)
+
+      expect(term.accepted_by_user?(user)).to be(true)
+    end
+
+    it 'is false when the user declined the terms' do
+      decline_terms(term, user)
+
+      expect(term.accepted_by_user?(user)).to be(false)
+    end
+
+    it 'does not cause a query when the user accepted the current terms' do
+      accept_terms(term, user)
+
+      expect { term.accepted_by_user?(user) }.not_to exceed_query_limit(0)
+    end
+
+    it 'returns false if the currently accepted terms are different' do
+      accept_terms(create(:term), user)
+
+      expect(term.accepted_by_user?(user)).to be(false)
+    end
+
+    def accept_terms(term, user)
+      Users::RespondToTermsService.new(user, term).execute(accepted: true)
+    end
+
+    def decline_terms(term, user)
+      Users::RespondToTermsService.new(user, term).execute(accepted: false)
+    end
+  end
 end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 0f072aa17192f3d36ea803e648869741e556e9f8..f6433234573cb7b46428c3a7a8670902169cb04c 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -549,7 +549,7 @@ describe Ci::Runner do
   end
 
   describe '#update_cached_info' do
-    let(:runner) { create(:ci_runner) }
+    let(:runner) { create(:ci_runner, :project) }
 
     subject { runner.update_cached_info(architecture: '18-bit') }
 
@@ -570,17 +570,22 @@ describe Ci::Runner do
         runner.contacted_at = 2.hours.ago
       end
 
-      it 'updates database' do
-        expect_redis_update
+      context 'with invalid runner' do
+        before do
+          runner.projects = []
+        end
+
+        it 'still updates redis cache and database' do
+          expect(runner).to be_invalid
 
-        expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
-          .and change { runner.reload.read_attribute(:architecture) }
+          expect_redis_update
+          does_db_update
+        end
       end
 
-      it 'updates cache' do
+      it 'updates redis cache and database' do
         expect_redis_update
-
-        subject
+        does_db_update
       end
     end
 
@@ -590,6 +595,11 @@ describe Ci::Runner do
         expect(redis).to receive(:set).with(redis_key, anything, any_args)
       end
     end
+
+    def does_db_update
+      expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
+        .and change { runner.reload.read_attribute(:architecture) }
+    end
   end
 
   describe '#destroy' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 65cc9372cbec9f4b6c6a20508f13aee85600ce43..3f028b3bd5c1cd342606bac7a76bccf884e707c8 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -16,7 +16,11 @@ describe MergeRequest do
 
   describe '#squash_in_progress?' do
     shared_examples 'checking whether a squash is in progress' do
-      let(:repo_path) { subject.source_project.repository.path }
+      let(:repo_path) do
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          subject.source_project.repository.path
+        end
+      end
       let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") }
 
       before do
@@ -2197,7 +2201,11 @@ describe MergeRequest do
 
   describe '#rebase_in_progress?' do
     shared_examples 'checking whether a rebase is in progress' do
-      let(:repo_path) { subject.source_project.repository.path }
+      let(:repo_path) do
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          subject.source_project.repository.path
+        end
+      end
       let(:rebase_path) { File.join(repo_path, "gitlab-worktree", "rebase-#{subject.id}") }
 
       before do
@@ -2237,25 +2245,25 @@ describe MergeRequest do
     end
   end
 
-  describe '#allow_maintainer_to_push' do
+  describe '#allow_collaboration' do
     let(:merge_request) do
-      build(:merge_request, source_branch: 'fixes', allow_maintainer_to_push: true)
+      build(:merge_request, source_branch: 'fixes', allow_collaboration: true)
     end
 
     it 'is false when pushing by a maintainer is not possible' do
-      expect(merge_request).to receive(:maintainer_push_possible?) { false }
+      expect(merge_request).to receive(:collaborative_push_possible?) { false }
 
-      expect(merge_request.allow_maintainer_to_push).to be_falsy
+      expect(merge_request.allow_collaboration).to be_falsy
     end
 
     it 'is true when pushing by a maintainer is possible' do
-      expect(merge_request).to receive(:maintainer_push_possible?) { true }
+      expect(merge_request).to receive(:collaborative_push_possible?) { true }
 
-      expect(merge_request.allow_maintainer_to_push).to be_truthy
+      expect(merge_request.allow_collaboration).to be_truthy
     end
   end
 
-  describe '#maintainer_push_possible?' do
+  describe '#collaborative_push_possible?' do
     let(:merge_request) do
       build(:merge_request, source_branch: 'fixes')
     end
@@ -2267,14 +2275,14 @@ describe MergeRequest do
     it 'does not allow maintainer to push if the source project is the same as the target' do
       merge_request.target_project = merge_request.source_project = create(:project, :public)
 
-      expect(merge_request.maintainer_push_possible?).to be_falsy
+      expect(merge_request.collaborative_push_possible?).to be_falsy
     end
 
     it 'allows maintainer to push when both source and target are public' do
       merge_request.target_project = build(:project, :public)
       merge_request.source_project = build(:project, :public)
 
-      expect(merge_request.maintainer_push_possible?).to be_truthy
+      expect(merge_request.collaborative_push_possible?).to be_truthy
     end
 
     it 'is not available for protected branches' do
@@ -2285,11 +2293,11 @@ describe MergeRequest do
                                    .with(merge_request.source_project, 'fixes')
                                    .and_return(true)
 
-      expect(merge_request.maintainer_push_possible?).to be_falsy
+      expect(merge_request.collaborative_push_possible?).to be_falsy
     end
   end
 
-  describe '#can_allow_maintainer_to_push?' do
+  describe '#can_allow_collaboration?' do
     let(:target_project) { create(:project, :public) }
     let(:source_project) { fork_project(target_project) }
     let(:merge_request) do
@@ -2301,17 +2309,17 @@ describe MergeRequest do
     let(:user) { create(:user) }
 
     before do
-      allow(merge_request).to receive(:maintainer_push_possible?) { true }
+      allow(merge_request).to receive(:collaborative_push_possible?) { true }
     end
 
     it 'is false if the user does not have push access to the source project' do
-      expect(merge_request.can_allow_maintainer_to_push?(user)).to be_falsy
+      expect(merge_request.can_allow_collaboration?(user)).to be_falsy
     end
 
     it 'is true when the user has push access to the source project' do
       source_project.add_developer(user)
 
-      expect(merge_request.can_allow_maintainer_to_push?(user)).to be_truthy
+      expect(merge_request.can_allow_collaboration?(user)).to be_truthy
     end
   end
 
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 6f702d8d95e83a81fad85489e793692d396056fe..18b01c3e6b7a662e50673b8a81c1cd82f64f47a3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -301,12 +301,18 @@ describe Namespace do
     end
 
     def project_rugged(project)
-      project.repository.rugged
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        project.repository.rugged
+      end
     end
   end
 
   describe '#rm_dir', 'callback' do
-    let(:repository_storage_path) { Gitlab.config.repositories.storages.default.legacy_disk_path }
+    let(:repository_storage_path) do
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.default.legacy_disk_path
+      end
+    end
     let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) }
     let(:deleted_path) { namespace.full_path.gsub(namespace.path, "#{namespace.full_path}+#{namespace.id}+deleted") }
     let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 9a76452a808e26bc87caf8b6e026b47bfadc4b90..fe9d64c0e3b83a488a666ef405c0ad54e5272c96 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3583,7 +3583,7 @@ describe Project do
         target_branch: 'target-branch',
         source_project: project,
         source_branch: 'awesome-feature-1',
-        allow_maintainer_to_push: true
+        allow_collaboration: true
       )
     end
 
@@ -3620,9 +3620,9 @@ describe Project do
       end
     end
 
-    describe '#branch_allows_maintainer_push?' do
+    describe '#branch_allows_collaboration_push?' do
       it 'allows access if the user can merge the merge request' do
-        expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+        expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
           .to be_truthy
       end
 
@@ -3630,7 +3630,7 @@ describe Project do
         guest = create(:user)
         target_project.add_guest(guest)
 
-        expect(project.branch_allows_maintainer_push?(guest, 'awesome-feature-1'))
+        expect(project.branch_allows_collaboration?(guest, 'awesome-feature-1'))
           .to be_falsy
       end
 
@@ -3640,31 +3640,31 @@ describe Project do
                target_branch: 'target-branch',
                source_project: project,
                source_branch: 'rejected-feature-1',
-               allow_maintainer_to_push: true)
+               allow_collaboration: true)
 
-        expect(project.branch_allows_maintainer_push?(user, 'rejected-feature-1'))
+        expect(project.branch_allows_collaboration?(user, 'rejected-feature-1'))
           .to be_falsy
       end
 
       it 'does not allow access if the user cannot merge the merge request' do
         create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch')
 
-        expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+        expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
           .to be_falsy
       end
 
       it 'caches the result' do
-        control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+        control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') }
 
-        expect { 3.times { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+        expect { 3.times { project.branch_allows_collaboration?(user, 'awesome-feature-1') } }
           .not_to exceed_query_limit(control)
       end
 
       context 'when the requeststore is active', :request_store do
         it 'only queries per project across instances' do
-          control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+          control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') }
 
-          expect { 2.times { described_class.find(project.id).branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+          expect { 2.times { described_class.find(project.id).branch_allows_collaboration?(user, 'awesome-feature-1') } }
             .not_to exceed_query_limit(control).with_threshold(2)
         end
       end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 0ccf55bd8950134927250ea0fba78acc25069b3d..c1aa7d80c943baf6ec8f370c2c6ab3cc2ad11c87 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -136,7 +136,10 @@ describe Repository do
         before do
           options = { message: 'test tag message\n',
                       tagger: { name: 'John Smith', email: 'john@gmail.com' } }
-          repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options)
+
+          Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options)
+          end
 
           double_first = double(committed_date: Time.now - 1.second)
           double_last = double(committed_date: Time.now)
@@ -1048,6 +1051,13 @@ describe Repository do
     let(:target_project) { project }
     let(:target_repository) { target_project.repository }
 
+    around do |example|
+      # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        example.run
+      end
+    end
+
     context 'when pre hooks were successful' do
       before do
         service = Gitlab::Git::HooksService.new
@@ -1309,6 +1319,13 @@ describe Repository do
   end
 
   describe '#update_autocrlf_option' do
+    around do |example|
+      # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        example.run
+      end
+    end
+
     describe 'when autocrlf is not already set to :input' do
       before do
         repository.raw_repository.autocrlf = true
@@ -1802,7 +1819,9 @@ describe Repository do
       expect(repository.branch_count).to be_an(Integer)
 
       # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync
-      rugged_count = repository.raw_repository.rugged.branches.count
+      rugged_count = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        repository.raw_repository.rugged.branches.count
+      end
 
       expect(repository.branch_count).to eq(rugged_count)
     end
@@ -1813,7 +1832,9 @@ describe Repository do
       expect(repository.tag_count).to be_an(Integer)
 
       # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync
-      rugged_count = repository.raw_repository.rugged.tags.count
+      rugged_count = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        repository.raw_repository.rugged.tags.count
+      end
 
       expect(repository.tag_count).to eq(rugged_count)
     end
@@ -2073,7 +2094,10 @@ describe Repository do
     it "attempting to call keep_around on truncated ref does not fail" do
       repository.keep_around(sample_commit.id)
       ref = repository.send(:keep_around_ref_name, sample_commit.id)
-      path = File.join(repository.path, ref)
+
+      path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        File.join(repository.path, ref)
+      end
       # Corrupt the reference
       File.truncate(path, 0)
 
@@ -2088,6 +2112,13 @@ describe Repository do
   end
 
   describe '#update_ref' do
+    around do |example|
+      # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        example.run
+      end
+    end
+
     it 'can create a ref' do
       Gitlab::Git::OperationService.new(nil, repository.raw_repository).send(:update_ref, 'refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA)
 
@@ -2372,7 +2403,9 @@ describe Repository do
   end
 
   def create_remote_branch(remote_name, branch_name, target)
-    rugged = repository.rugged
+    rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      repository.rugged
+    end
     rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target.id)
   end
 
diff --git a/spec/models/term_agreement_spec.rb b/spec/models/term_agreement_spec.rb
index a59bf1196926374b1f0c17a93bd33c99cf72e6f7..950dfa09a6a68843652db924a467d071e9b02add 100644
--- a/spec/models/term_agreement_spec.rb
+++ b/spec/models/term_agreement_spec.rb
@@ -5,4 +5,13 @@ describe TermAgreement do
     it { is_expected.to validate_presence_of(:term) }
     it { is_expected.to validate_presence_of(:user) }
   end
+
+  describe '.accepted' do
+    it 'only includes accepted terms' do
+      accepted = create(:term_agreement, :accepted)
+      create(:term_agreement, :declined)
+
+      expect(described_class.accepted).to contain_exactly(accepted)
+    end
+  end
 end
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index 9ca156deaa079ff9b7042247e22ef6fbe45c2809..eead55d33ca5c0c27c3ccdadb9166205754756f7 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -101,7 +101,7 @@ describe Ci::BuildPolicy do
 
         it 'enables update_build if user is maintainer' do
           allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
-          allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true)
+          allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true)
 
           expect(policy).to be_allowed :update_build
           expect(policy).to be_allowed :update_commit_status
diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb
index a5e509cfa0fadf780c385d2873a9f55dc8ca96e4..bd32faf06ef746af9b950cc1031476babd6b1236 100644
--- a/spec/policies/ci/pipeline_policy_spec.rb
+++ b/spec/policies/ci/pipeline_policy_spec.rb
@@ -69,7 +69,7 @@ describe Ci::PipelinePolicy, :models do
 
       it 'enables update_pipeline if user is maintainer' do
         allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
-        allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true)
+        allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true)
 
         expect(policy).to be_allowed :update_pipeline
       end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 6609f5f7afdc351fd3f6ecea8112abd2c19d2b28..6ac151f92f3d6dd77d9207439146911ec5bf4312 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -400,7 +400,7 @@ describe ProjectPolicy do
         :merge_request,
         target_project: target_project,
         source_project: project,
-        allow_maintainer_to_push: true
+        allow_collaboration: true
       )
     end
     let(:maintainer_abilities) do
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index 962c845f36d3d888caf8d1b5178d225fdc2b81bc..e6a61fdcf392611465a1862aab50ed9b703880bb 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -176,7 +176,7 @@ describe API::Events do
       end
 
       it 'avoids N+1 queries' do
-        control_count = ActiveRecord::QueryRecorder.new do
+        control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
           get api("/projects/#{private_project.id}/events", user), target_type: :merge_request
         end.count
 
@@ -184,7 +184,7 @@ describe API::Events do
 
         expect do
           get api("/projects/#{private_project.id}/events", user), target_type: :merge_request
-        end.not_to exceed_query_limit(control_count)
+        end.not_to exceed_all_query_limit(control_count)
 
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 605761867bf6f45c1b2a105e7b54b58e485e94f7..d4ebfc3f782f4bede70f3f44b2b14937151e7fc2 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -386,12 +386,13 @@ describe API::MergeRequests do
                source_project: forked_project,
                target_project: project,
                source_branch: 'fixes',
-               allow_maintainer_to_push: true)
+               allow_collaboration: true)
       end
 
-      it 'includes the `allow_maintainer_to_push` field' do
+      it 'includes the `allow_collaboration` field' do
         get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
 
+        expect(json_response['allow_collaboration']).to be_truthy
         expect(json_response['allow_maintainer_to_push']).to be_truthy
       end
     end
@@ -654,11 +655,12 @@ describe API::MergeRequests do
         expect(response).to have_gitlab_http_status(400)
       end
 
-      it 'allows setting `allow_maintainer_to_push`' do
+      it 'allows setting `allow_collaboration`' do
         post api("/projects/#{forked_project.id}/merge_requests", user2),
-          title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master",
-          author: user2, target_project_id: project.id, allow_maintainer_to_push: true
+             title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master",
+             author: user2, target_project_id: project.id, allow_collaboration: true
         expect(response).to have_gitlab_http_status(201)
+        expect(json_response['allow_collaboration']).to be_truthy
         expect(json_response['allow_maintainer_to_push']).to be_truthy
       end
 
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index e2b19ad59f92d6ad78b123b5d7a8a608d5080304..969710d6613a7f86e47393b1214d6118c52e0078 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -287,7 +287,10 @@ describe API::Tags do
       context 'annotated tag' do
         it 'creates a new annotated tag' do
           # Identity must be set in .gitconfig to create annotated tag.
-          repo_path = project.repository.path_to_repo
+          repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            project.repository.path_to_repo
+          end
+
           system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name}))
           system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email}))
 
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index a73bd7a0268a131df4d8bcee0baaf83b3b54cd03..688d3b8c03808201b31bf65e6de0dfc57fe673d2 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -280,12 +280,12 @@ describe Ci::RetryPipelineService, '#execute' do
         source_project: forked_project,
         target_project: project,
         source_branch: 'fixes',
-        allow_maintainer_to_push: true)
+        allow_collaboration: true)
       create_build('rspec 1', :failed, 1)
     end
 
     it 'allows to retry failed pipeline' do
-      allow_any_instance_of(Project).to receive(:fetch_branch_allows_maintainer_push?).and_return(true)
+      allow_any_instance_of(Project).to receive(:fetch_branch_allows_collaboration?).and_return(true)
       allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
 
       service.execute(pipeline)
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index bd2e91f1f7a5d6989d73282c10723e293d3bc1b1..443dcd92a8b2e31ea36cdb84d8483ff0b04fe714 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -547,7 +547,7 @@ describe MergeRequests::UpdateService, :mailer do
       let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
     end
 
-    context 'setting `allow_maintainer_to_push`' do
+    context 'setting `allow_collaboration`' do
       let(:target_project) { create(:project, :public) }
       let(:source_project) { fork_project(target_project) }
       let(:user) { create(:user) }
@@ -562,23 +562,23 @@ describe MergeRequests::UpdateService, :mailer do
         allow(ProtectedBranch).to receive(:protected?).with(source_project, 'fixes') { false }
       end
 
-      it 'does not allow a maintainer of the target project to set `allow_maintainer_to_push`' do
+      it 'does not allow a maintainer of the target project to set `allow_collaboration`' do
         target_project.add_developer(user)
 
-        update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+        update_merge_request(allow_collaboration: true, title: 'Updated title')
 
         expect(merge_request.title).to eq('Updated title')
-        expect(merge_request.allow_maintainer_to_push).to be_falsy
+        expect(merge_request.allow_collaboration).to be_falsy
       end
 
       it 'is allowed by a user that can push to the source and can update the merge request' do
         merge_request.update!(assignee: user)
         source_project.add_developer(user)
 
-        update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+        update_merge_request(allow_collaboration: true, title: 'Updated title')
 
         expect(merge_request.title).to eq('Updated title')
-        expect(merge_request.allow_maintainer_to_push).to be_truthy
+        expect(merge_request.allow_collaboration).to be_truthy
       end
     end
   end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 3e6483d7e28b4f4287222abe5f6f262417a1b4ed..5100987c2fec89e57658b014b9ff480df93eb553 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -64,7 +64,7 @@ describe Projects::TransferService do
     it 'updates project full path in .git/config' do
       transfer_project(project, user, group)
 
-      expect(project.repository.rugged.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
+      expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
     end
   end
 
@@ -84,7 +84,9 @@ describe Projects::TransferService do
     end
 
     def project_path(project)
-      project.repository.path_to_repo
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        project.repository.path_to_repo
+      end
     end
 
     def current_path
@@ -101,7 +103,7 @@ describe Projects::TransferService do
     it 'rolls back project full path in .git/config' do
       attempt_project_transfer
 
-      expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
+      expect(rugged_config['gitlab.fullpath']).to eq project.full_path
     end
 
     it "doesn't send move notifications" do
@@ -264,4 +266,10 @@ describe Projects::TransferService do
       transfer_project(project, owner, group)
     end
   end
+
+  def rugged_config
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.rugged.config
+    end
+  end
 end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 1f761bcbbad182a960dd41e0f97b310aaa212c59..ecf1ba056183c0d7035a7efee62b480e19786d67 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -125,7 +125,7 @@ describe Projects::UpdateService do
 
     context 'when we update project but not enabling a wiki' do
       it 'does not try to create an empty wiki' do
-        FileUtils.rm_rf(project.wiki.repository.path)
+        Gitlab::Shell.new.rm_directory(project.repository_storage, project.wiki.path)
 
         result = update_project(project, user, { name: 'test1' })
 
@@ -146,7 +146,7 @@ describe Projects::UpdateService do
     context 'when enabling a wiki' do
       it 'creates a wiki' do
         project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
-        FileUtils.rm_rf(project.wiki.repository.path)
+        Gitlab::Shell.new.rm_directory(project.repository_storage, project.wiki.path)
 
         result = update_project(project, user, project_feature_attributes: { wiki_access_level: ProjectFeature::ENABLED })
 
diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb
index 962b9f40c4fd3016d4ed247e39e98ed7a9290708..19e1c5ff3b25a98906be20818eceeb5d884e9f7d 100644
--- a/spec/services/test_hooks/project_service_spec.rb
+++ b/spec/services/test_hooks/project_service_spec.rb
@@ -6,13 +6,19 @@ describe TestHooks::ProjectService do
   describe '#execute' do
     let(:project) { create(:project, :repository) }
     let(:hook)    { create(:project_hook, project: project) }
+    let(:trigger) { 'not_implemented_events' }
     let(:service) { described_class.new(hook, current_user, trigger) }
     let(:sample_data) { { data: 'sample' } }
     let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }
 
-    context 'hook with not implemented test' do
-      let(:trigger) { 'not_implemented_events' }
+    it 'allows to set a custom project' do
+      project = double
+      service.project = project
+
+      expect(service.project).to eq(project)
+    end
 
+    context 'hook with not implemented test' do
       it 'returns error message' do
         expect(hook).not_to receive(:execute)
         expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' })
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d3de2331244b6f94208a21d2780cfe250618e708..e093444121a725e1e102026b18b2bed23c276b9f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -133,6 +133,10 @@ RSpec.configure do |config|
     RequestStore.clear!
   end
 
+  config.after(:example) do
+    Fog.unmock! if Fog.mock?
+  end
+
   config.before(:example, :mailer) do
     reset_delivered_emails!
   end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 06a76d53354d84f515e5c6b350f360bc67e15df3..32d9807f06a6301d65e0c2ed0a1e682b8d6c426e 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -123,7 +123,11 @@ module CycleAnalyticsHelpers
 
       if branch_update.newrev
         _, opts = args
-        commit = raw_repository.commit(branch_update.newrev).rugged_commit
+
+        commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          raw_repository.commit(branch_update.newrev).rugged_commit
+        end
+
         branch_update.newrev = commit.amend(
           update_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{opts[:branch_name]}",
           author: commit.author.merge(time: new_date),
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index c9252bebb2e0791d0494e564749c7422bf92490f..93a436cb2b54c1447059c4f7264132c3dd6e1114 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -101,7 +101,9 @@ describe 'gitlab:app namespace rake task' do
 
       before do
         stub_env('SKIP', 'db')
-        path = File.join(project.repository.path_to_repo, 'custom_hooks')
+        path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          File.join(project.repository.path_to_repo, 'custom_hooks')
+        end
         FileUtils.mkdir_p(path)
         FileUtils.touch(File.join(path, "dummy.txt"))
       end
@@ -122,7 +124,10 @@ describe 'gitlab:app namespace rake task' do
           expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout
           expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout
 
-          expect(Dir.entries(File.join(project.repository.path, 'custom_hooks'))).to include("dummy.txt")
+          repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            project.repository.path
+          end
+          expect(Dir.entries(File.join(repo_path, 'custom_hooks'))).to include("dummy.txt")
         end
       end
 
@@ -243,10 +248,12 @@ describe 'gitlab:app namespace rake task' do
         FileUtils.mkdir_p(b_storage_dir)
 
         # Even when overriding the storage, we have to move it there, so it exists
-        FileUtils.mv(
-          File.join(Settings.absolute(storages['default'].legacy_disk_path), project_b.repository.disk_path + '.git'),
-          Rails.root.join(storages['test_second_storage'].legacy_disk_path, project_b.repository.disk_path + '.git')
-        )
+        Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          FileUtils.mv(
+            File.join(Settings.absolute(storages['default'].legacy_disk_path), project_b.repository.disk_path + '.git'),
+            Rails.root.join(storages['test_second_storage'].legacy_disk_path, project_b.repository.disk_path + '.git')
+          )
+        end
 
         expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout
 
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index 01166865e8880efd1e971f0529a2c42595184156..4503288e410bee3118cfcf933af423df238fbf2b 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -360,13 +360,6 @@ describe ObjectStorage do
 
     subject { uploader_class.workhorse_authorize(has_length: has_length, maximum_size: maximum_size) }
 
-    before do
-      # ensure that we use regular Fog libraries
-      # other tests might call `Fog.mock!` and
-      # it will make tests to fail
-      Fog.unmock!
-    end
-
     shared_examples 'uses local storage' do
       it "returns temporary path" do
         is_expected.to have_key(:TempPath)
@@ -739,4 +732,26 @@ describe ObjectStorage do
       end
     end
   end
+
+  describe '#retrieve_from_store!' do
+    [:group, :project, :user].each do |model|
+      context "for #{model}s" do
+        let(:models) { create_list(model, 3, :with_avatar).map(&:reload) }
+        let(:avatars) { models.map(&:avatar) }
+
+        it 'batches fetching uploads from the database' do
+          # Ensure that these are all created and fully loaded before we start
+          # running queries for avatars
+          models
+
+          expect { avatars }.not_to exceed_query_limit(1)
+        end
+
+        it 'fetches a unique upload for each model' do
+          expect(avatars.map(&:url).uniq).to eq(avatars.map(&:url))
+          expect(avatars.map(&:upload).uniq).to eq(avatars.map(&:upload))
+        end
+      end
+    end
+  end
 end
diff --git a/spec/uploaders/workers/object_storage/background_move_worker_spec.rb b/spec/uploaders/workers/object_storage/background_move_worker_spec.rb
index b34f427fd8a3fb793949d96ba96eb0f79bac782d..95813d15e52fc8ed8abd4cee7e974a0e253750e7 100644
--- a/spec/uploaders/workers/object_storage/background_move_worker_spec.rb
+++ b/spec/uploaders/workers/object_storage/background_move_worker_spec.rb
@@ -125,8 +125,10 @@ describe ObjectStorage::BackgroundMoveWorker do
 
           it "migrates file to remote storage" do
             perform
+            project.reload
+            BatchLoader::Executor.clear_current
 
-            expect(project.reload.avatar.file_storage?).to be_falsey
+            expect(project.avatar).not_to be_file_storage
           end
         end
 
@@ -137,7 +139,7 @@ describe ObjectStorage::BackgroundMoveWorker do
           it "migrates file to remote storage" do
             perform
 
-            expect(project.reload.avatar.file_storage?).to be_falsey
+            expect(project.reload.avatar).not_to be_file_storage
           end
         end
       end
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index a021235aed6e3fcdeea4fada9e113b6bf42f9f13..22fc64c15365ebeab174161169f691ca159a8ec2 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -88,7 +88,9 @@ describe RepositoryCheck::SingleRepositoryWorker do
   end
 
   def break_wiki(project)
-    break_repo(wiki_path(project))
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      break_repo(wiki_path(project))
+    end
   end
 
   def wiki_path(project)
@@ -96,7 +98,9 @@ describe RepositoryCheck::SingleRepositoryWorker do
   end
 
   def break_project(project)
-    break_repo(project.repository.path_to_repo)
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      break_repo(project.repository.path_to_repo)
+    end
   end
 
   def break_repo(repo)