summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/controllers/application_controller.rb1
-rw-r--r--app/controllers/concerns/sessionless_authentication.rb12
-rw-r--r--app/controllers/graphql_controller.rb5
-rw-r--r--app/controllers/groups_controller.rb3
-rw-r--r--app/models/deployment.rb6
-rw-r--r--app/models/environment.rb9
-rw-r--r--app/models/namespace.rb4
-rw-r--r--app/models/project.rb6
-rw-r--r--app/models/protected_branch.rb10
-rw-r--r--app/services/issues/import_csv_service.rb15
-rw-r--r--app/services/projects/protect_default_branch_service.rb2
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml5
-rw-r--r--app/views/groups/settings/_permissions.html.haml1
-rw-r--r--app/views/shared/_default_branch_protection.html.haml3
-rw-r--r--changelogs/unreleased/193170-fix-deployment-ref-validation.yml5
-rw-r--r--changelogs/unreleased/207927-validate-actor-user-against-codeowners.yml5
-rw-r--r--changelogs/unreleased/208151-code-review-analytics-shows-no-data-for-mrs-in-review-for-less-tha.yml5
-rw-r--r--changelogs/unreleased/7583-developer-cannot-push-to-projects-they-create-in-groups.yml5
-rw-r--r--changelogs/unreleased/jhyson-issue-import-export-consistency.yml5
-rw-r--r--changelogs/unreleased/refactor-bypass-session-admin-mode.yml5
-rw-r--r--config/application.rb7
-rw-r--r--config/initializers_before_autoloader/000_inflections.rb (renamed from config/initializers/0_inflections.rb)0
-rw-r--r--db/migrate/20200207062728_add_default_branch_protection_to_namespaces.rb13
-rw-r--r--db/schema.rb1
-rw-r--r--doc/api/groups.md15
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/database_review.md2
-rw-r--r--doc/development/migration_style_guide.md4
-rw-r--r--doc/development/rails_initializers.md16
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md2
-rw-r--r--doc/user/group/index.md15
-rw-r--r--doc/user/project/issues/csv_import.md8
-rw-r--r--lib/api/api_guard.rb28
-rw-r--r--lib/api/entities/group.rb1
-rw-r--r--lib/api/helpers/groups_helpers.rb1
-rw-r--r--lib/gitlab/access/branch_protection.rb4
-rw-r--r--lib/gitlab/auth/current_user_mode.rb23
-rw-r--r--lib/gitlab/graphql/connections.rb4
-rw-r--r--lib/gitlab/graphql/pagination/offset_active_record_relation_connection.rb13
-rw-r--r--lib/gitlab/graphql/pagination/relations/offset_active_record_relation.rb12
-rw-r--r--package.json2
-rw-r--r--scripts/review_apps/base-config.yaml24
-rw-r--r--spec/controllers/groups_controller_spec.rb7
-rw-r--r--spec/fixtures/csv_gitlab_export.csv5
-rw-r--r--spec/graphql/gitlab_schema_spec.rb23
-rw-r--r--spec/lib/gitlab/access/branch_protection_spec.rb17
-rw-r--r--spec/lib/gitlab/auth/current_user_mode_spec.rb404
-rw-r--r--spec/lib/gitlab/graphql/pagination/offset_active_record_relation_connection_spec.rb9
-rw-r--r--spec/lib/gitlab/user_access_spec.rb47
-rw-r--r--spec/models/deployment_spec.rb15
-rw-r--r--spec/models/environment_spec.rb20
-rw-r--r--spec/models/namespace_spec.rb35
-rw-r--r--spec/models/project_spec.rb29
-rw-r--r--spec/models/protected_branch_spec.rb48
-rw-r--r--spec/requests/api/api_guard/admin_mode_middleware_spec.rb35
-rw-r--r--spec/requests/api/graphql/group_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb2
-rw-r--r--spec/requests/api/groups_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb2
-rw-r--r--spec/services/deployments/after_create_service_spec.rb2
-rw-r--r--spec/services/git/branch_push_service_spec.rb8
-rw-r--r--spec/services/issues/import_csv_service_spec.rb50
-rw-r--r--spec/services/projects/protect_default_branch_service_spec.rb14
-rw-r--r--spec/support/helpers/wait_for_requests.rb4
-rw-r--r--yarn.lock8
67 files changed, 743 insertions, 361 deletions
diff --git a/Gemfile b/Gemfile
index 40aca12aea8..16e4ef12fe0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -420,7 +420,7 @@ end
gem 'octokit', '~> 4.15'
# https://gitlab.com/gitlab-org/gitlab/issues/207207
-gem 'gitlab-mail_room', '~> 0.0.2', require: 'mail_room'
+gem 'gitlab-mail_room', '~> 0.0.3', require: 'mail_room'
gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text'
diff --git a/Gemfile.lock b/Gemfile.lock
index 38de70b41ef..b11f0c5a5db 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -388,7 +388,7 @@ GEM
opentracing (~> 0.4)
redis (> 3.0.0, < 5.0.0)
gitlab-license (1.0.0)
- gitlab-mail_room (0.0.2)
+ gitlab-mail_room (0.0.3)
gitlab-markup (1.7.0)
gitlab-net-dns (0.9.1)
gitlab-puma (4.3.1.gitlab.2)
@@ -1235,7 +1235,7 @@ DEPENDENCIES
gitlab-chronic (~> 0.10.5)
gitlab-labkit (= 0.10.0)
gitlab-license (~> 1.0)
- gitlab-mail_room (~> 0.0.2)
+ gitlab-mail_room (~> 0.0.3)
gitlab-markup (~> 1.7.0)
gitlab-net-dns (~> 0.9.1)
gitlab-puma (~> 4.3.1.gitlab.2)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7cb629dee21..5a2eb2337aa 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -34,6 +34,7 @@ class ApplicationController < ActionController::Base
before_action :check_impersonation_availability
before_action :required_signup_info
+ around_action :sessionless_bypass_admin_mode!, if: :sessionless_user?
around_action :set_current_context
around_action :set_locale
around_action :set_session_storage
diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb
index d5c26fca957..a9ef33bf3b9 100644
--- a/app/controllers/concerns/sessionless_authentication.rb
+++ b/app/controllers/concerns/sessionless_authentication.rb
@@ -5,12 +5,6 @@
# Controller concern to handle PAT, RSS, and static objects token authentication methods
#
module SessionlessAuthentication
- extend ActiveSupport::Concern
-
- included do
- before_action :enable_admin_mode!, if: :sessionless_user?
- end
-
# This filter handles personal access tokens, atom requests with rss tokens, and static object tokens
def authenticate_sessionless_user!(request_format)
user = Gitlab::Auth::RequestAuthenticator.new(request).find_sessionless_user(request_format)
@@ -32,9 +26,9 @@ module SessionlessAuthentication
end
end
- def enable_admin_mode!
- return unless Feature.enabled?(:user_mode_in_session)
+ def sessionless_bypass_admin_mode!(&block)
+ return yield unless Feature.enabled?(:user_mode_in_session)
- current_user_mode.enable_sessionless_admin_mode!
+ Gitlab::Auth::CurrentUserMode.bypass_session!(current_user.id, &block)
end
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index d7ff2ded5ae..522d171b5bf 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -15,6 +15,11 @@ class GraphqlController < ApplicationController
before_action :authorize_access_api!
before_action(only: [:execute]) { authenticate_sessionless_user!(:api) }
+ # Since we deactivate authentication from the main ApplicationController and
+ # defer it to :authorize_access_api!, we need to override the bypass session
+ # callback execution order here
+ around_action :sessionless_bypass_admin_mode!, if: :sessionless_user?
+
def execute
result = multiplex? ? execute_multiplex : execute_query
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 80c7a803392..7175eefcde7 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -195,7 +195,8 @@ class GroupsController < Groups::ApplicationController
:require_two_factor_authentication,
:two_factor_grace_period,
:project_creation_level,
- :subgroup_creation_level
+ :subgroup_creation_level,
+ :default_branch_protection
]
end
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index fbb59173a3c..b118404b916 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -135,7 +135,7 @@ class Deployment < ApplicationRecord
end
def create_ref
- project.repository.create_ref(ref, ref_path)
+ project.repository.create_ref(sha, ref_path)
end
def invalidate_cache
@@ -280,12 +280,12 @@ class Deployment < ApplicationRecord
errors.add(:ref, _('The branch or tag does not exist'))
end
- private
-
def ref_path
File.join(environment.ref_path, 'deployments', iid.to_s)
end
+ private
+
def legacy_finished_at
self.created_at if success? && !read_attribute(:finished_at)
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 4224a32a6d7..0e2962b893a 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -193,15 +193,6 @@ class Environment < ApplicationRecord
folder_name == "production"
end
- def first_deployment_for(commit_sha)
- ref = project.repository.ref_name_for_sha(ref_path, commit_sha)
-
- return unless ref
-
- deployment_iid = ref.split('/').last
- deployments.find_by(iid: deployment_iid)
- end
-
def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 99212d09b8e..f06e9da3b2a 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -139,6 +139,10 @@ class Namespace < ApplicationRecord
end
end
+ def default_branch_protection
+ super || Gitlab::CurrentSettings.default_branch_protection
+ end
+
def visibility_level_field
:visibility_level
end
diff --git a/app/models/project.rb b/app/models/project.rb
index f72e777c004..fdf7452d143 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2359,6 +2359,12 @@ class Project < ApplicationRecord
Gitlab::Routing.url_helpers.revoke_project_deploy_token_path(self, token)
end
+ def default_branch_protected?
+ branch_protection = Gitlab::Access::BranchProtection.new(self.namespace.default_branch_protection)
+
+ branch_protection.fully_protected? || branch_protection.developer_can_merge?
+ end
+
private
def closest_namespace_setting(name)
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 94c3b83564f..594c822c18f 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -11,7 +11,8 @@ class ProtectedBranch < ApplicationRecord
def self.protected_ref_accessible_to?(ref, user, project:, action:, protected_refs: nil)
# Maintainers, owners and admins are allowed to create the default branch
- if default_branch_protected? && project.empty_repo?
+
+ if project.empty_repo? && project.default_branch_protected?
return true if user.admin? || project.team.max_member_access(user.id) > Gitlab::Access::DEVELOPER
end
@@ -20,7 +21,7 @@ class ProtectedBranch < ApplicationRecord
# Check if branch name is marked as protected in the system
def self.protected?(project, ref_name)
- return true if project.empty_repo? && default_branch_protected?
+ return true if project.empty_repo? && project.default_branch_protected?
self.matching(ref_name, protected_refs: protected_refs(project)).present?
end
@@ -33,11 +34,6 @@ class ProtectedBranch < ApplicationRecord
end
end
- def self.default_branch_protected?
- Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_FULL ||
- Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE
- end
-
def self.protected_refs(project)
project.protected_branches
end
diff --git a/app/services/issues/import_csv_service.rb b/app/services/issues/import_csv_service.rb
index ef08fafa7cc..c01db5fcfe6 100644
--- a/app/services/issues/import_csv_service.rb
+++ b/app/services/issues/import_csv_service.rb
@@ -21,8 +21,19 @@ module Issues
def process_csv
csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
- CSV.new(csv_data, col_sep: detect_col_sep(csv_data.lines.first), headers: true).each.with_index(2) do |row, line_no|
- issue = Issues::CreateService.new(@project, @user, title: row[0], description: row[1]).execute
+ csv_parsing_params = {
+ col_sep: detect_col_sep(csv_data.lines.first),
+ headers: true,
+ header_converters: :symbol
+ }
+
+ CSV.new(csv_data, csv_parsing_params).each.with_index(2) do |row, line_no|
+ issue_attributes = {
+ title: row[:title],
+ description: row[:description]
+ }
+
+ issue = Issues::CreateService.new(@project, @user, issue_attributes).execute
if issue.persisted?
@results[:success] += 1
diff --git a/app/services/projects/protect_default_branch_service.rb b/app/services/projects/protect_default_branch_service.rb
index 245490791bf..1d3fb523448 100644
--- a/app/services/projects/protect_default_branch_service.rb
+++ b/app/services/projects/protect_default_branch_service.rb
@@ -11,7 +11,7 @@ module Projects
@project = project
@default_branch_protection = Gitlab::Access::BranchProtection
- .new(Gitlab::CurrentSettings.default_branch_protection)
+ .new(project.namespace.default_branch_protection)
end
def execute
diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml
index ae90ffd9efc..a4acbe6c885 100644
--- a/app/views/admin/application_settings/_visibility_and_access.html.haml
+++ b/app/views/admin/application_settings/_visibility_and_access.html.haml
@@ -2,9 +2,8 @@
= form_errors(@application_setting)
%fieldset
- .form-group
- = f.label :default_branch_protection, class: 'label-bold'
- = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
+ = render 'shared/default_branch_protection', f: f, selected_level: @application_setting.default_branch_protection
+
.form-group
= f.label s_('ProjectCreationLevel|Default project creation protection'), class: 'label-bold'
= f.select :default_project_creation, options_for_select(Gitlab::Access.project_creation_options, @application_setting.default_project_creation), {}, class: 'form-control'
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index 618cfe57be4..016a9c8e054 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -33,6 +33,7 @@
= render_if_exists 'groups/settings/ip_restriction', f: f, group: @group
= render_if_exists 'groups/settings/allowed_email_domain', f: f, group: @group
= render 'groups/settings/lfs', f: f
+ = render 'shared/default_branch_protection', f: f, selected_level: @group.default_branch_protection
= render 'groups/settings/project_creation_level', f: f, group: @group
= render 'groups/settings/subgroup_creation_level', f: f, group: @group
= render 'groups/settings/two_factor_auth', f: f
diff --git a/app/views/shared/_default_branch_protection.html.haml b/app/views/shared/_default_branch_protection.html.haml
new file mode 100644
index 00000000000..d7ae21debd8
--- /dev/null
+++ b/app/views/shared/_default_branch_protection.html.haml
@@ -0,0 +1,3 @@
+.form-group
+ = f.label :default_branch_protection, class: 'label-bold'
+ = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, selected_level), {}, class: 'form-control'
diff --git a/changelogs/unreleased/193170-fix-deployment-ref-validation.yml b/changelogs/unreleased/193170-fix-deployment-ref-validation.yml
new file mode 100644
index 00000000000..921cf96b7ba
--- /dev/null
+++ b/changelogs/unreleased/193170-fix-deployment-ref-validation.yml
@@ -0,0 +1,5 @@
+---
+title: Use of sha instead of ref when creating a new ref on deployment creation.
+merge_request: 23170
+author:
+type: fixed
diff --git a/changelogs/unreleased/207927-validate-actor-user-against-codeowners.yml b/changelogs/unreleased/207927-validate-actor-user-against-codeowners.yml
new file mode 100644
index 00000000000..cbdfaa48c44
--- /dev/null
+++ b/changelogs/unreleased/207927-validate-actor-user-against-codeowners.yml
@@ -0,0 +1,5 @@
+---
+title: Validate actor against CODEOWNERS entries
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/208151-code-review-analytics-shows-no-data-for-mrs-in-review-for-less-tha.yml b/changelogs/unreleased/208151-code-review-analytics-shows-no-data-for-mrs-in-review-for-less-tha.yml
new file mode 100644
index 00000000000..a891fe33277
--- /dev/null
+++ b/changelogs/unreleased/208151-code-review-analytics-shows-no-data-for-mrs-in-review-for-less-tha.yml
@@ -0,0 +1,5 @@
+---
+title: 'Code Review Analytics: Fix review time display'
+merge_request: 26057
+author:
+type: fixed
diff --git a/changelogs/unreleased/7583-developer-cannot-push-to-projects-they-create-in-groups.yml b/changelogs/unreleased/7583-developer-cannot-push-to-projects-they-create-in-groups.yml
new file mode 100644
index 00000000000..2055abc4551
--- /dev/null
+++ b/changelogs/unreleased/7583-developer-cannot-push-to-projects-they-create-in-groups.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce default branch protection at the group level
+merge_request: 24426
+author:
+type: added
diff --git a/changelogs/unreleased/jhyson-issue-import-export-consistency.yml b/changelogs/unreleased/jhyson-issue-import-export-consistency.yml
new file mode 100644
index 00000000000..0d2b8167d94
--- /dev/null
+++ b/changelogs/unreleased/jhyson-issue-import-export-consistency.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue importer so it matches issue export format
+merge_request: 25896
+author:
+type: fixed
diff --git a/changelogs/unreleased/refactor-bypass-session-admin-mode.yml b/changelogs/unreleased/refactor-bypass-session-admin-mode.yml
new file mode 100644
index 00000000000..902f3239fd0
--- /dev/null
+++ b/changelogs/unreleased/refactor-bypass-session-admin-mode.yml
@@ -0,0 +1,5 @@
+---
+title: Sessionless and API endpoints bypass session for admin mode
+merge_request: 25056
+author: Diego Louzán
+type: changed
diff --git a/config/application.rb b/config/application.rb
index 2f4d271322f..d0bb411c3cc 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -292,6 +292,13 @@ module Gitlab
initializer :move_initializers, before: :load_config_initializers, after: :let_zeitwerk_take_over do
end
+ # We need this for initializers that need to be run before Zeitwerk is loaded
+ initializer :before_zeitwerk, before: :let_zeitwerk_take_over, after: :prepend_helpers_path do
+ Dir[Rails.root.join('config/initializers_before_autoloader/*.rb')].sort.each do |initializer|
+ load_config_initializer(initializer)
+ end
+ end
+
config.after_initialize do
Rails.application.reload_routes!
diff --git a/config/initializers/0_inflections.rb b/config/initializers_before_autoloader/000_inflections.rb
index 1fabce9a57e..1fabce9a57e 100644
--- a/config/initializers/0_inflections.rb
+++ b/config/initializers_before_autoloader/000_inflections.rb
diff --git a/db/migrate/20200207062728_add_default_branch_protection_to_namespaces.rb b/db/migrate/20200207062728_add_default_branch_protection_to_namespaces.rb
new file mode 100644
index 00000000000..c21cac307f9
--- /dev/null
+++ b/db/migrate/20200207062728_add_default_branch_protection_to_namespaces.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddDefaultBranchProtectionToNamespaces < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ with_lock_retries do
+ add_column :namespaces, :default_branch_protection, :integer, limit: 2
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 149582f94bf..fa251f65741 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -2762,6 +2762,7 @@ ActiveRecord::Schema.define(version: 2020_02_26_162723) do
t.integer "max_pages_size"
t.integer "max_artifacts_size"
t.boolean "mentions_disabled"
+ t.integer "default_branch_protection", limit: 2
t.index ["created_at"], name: "index_namespaces_on_created_at"
t.index ["custom_project_templates_group_id", "type"], name: "index_namespaces_on_custom_project_templates_group_id_and_type", where: "(custom_project_templates_group_id IS NOT NULL)"
t.index ["file_template_project_id"], name: "index_namespaces_on_file_template_project_id"
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 3a488ca6546..e48cb78b2cc 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -42,6 +42,7 @@ GET /groups
"emails_disabled": null,
"mentions_disabled": null,
"lfs_enabled": true,
+ "default_branch_protection": 2,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar",
"request_access_enabled": false,
@@ -76,6 +77,7 @@ GET /groups?statistics=true
"emails_disabled": null,
"mentions_disabled": null,
"lfs_enabled": true,
+ "default_branch_protection": 2,
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
"web_url": "http://localhost:3000/groups/foo-bar",
"request_access_enabled": false,
@@ -148,6 +150,7 @@ GET /groups/:id/subgroups
"emails_disabled": null,
"mentions_disabled": null,
"lfs_enabled": true,
+ "default_branch_protection": 2,
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
"web_url": "http://gitlab.example.com/groups/foo-bar",
"request_access_enabled": false,
@@ -493,9 +496,20 @@ Parameters:
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
| `request_access_enabled` | boolean | no | Allow users to request member access. |
| `parent_id` | integer | no | The parent group ID for creating nested group. |
+| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). Default to the global level default branch protection setting. |
| `shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Pipeline minutes quota for this group. |
| `extra_shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Extra pipeline minutes quota for this group. |
+### Options for `default_branch_protection`
+
+The `default_branch_protection` attribute determines whether developers and maintainers can push to the applicable master branch, as described in the following table:
+
+| Value | Description |
+|-------|-------------------------------------------------------------------------------------------------------------|
+| `0` | No protection. Developers and maintainers can: <br>- Push new commits<br>- Force push changes<br>- Delete the branch |
+| `1` | Partial protection. Developers and maintainers can: <br>- Push new commits |
+| `2` | Full protection. Only maintainers can: <br>- Push new commits |
+
## Transfer project to group
Transfer a project to the Group namespace. Available only to instance administrators, although an [alternative API endpoint](projects.md#transfer-a-project-to-a-new-namespace) is available which does not require instance administrator access. Transferring projects may fail when tagged packages exist in the project's repository.
@@ -542,6 +556,7 @@ PUT /groups/:id
| `mentions_disabled` | boolean | no | Disable the capability of a group from getting mentioned |
| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
| `request_access_enabled` | boolean | no | Allow users to request member access. |
+| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). |
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. |
| `shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Pipeline minutes quota for this group. |
| `extra_shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Extra pipeline minutes quota for this group. |
diff --git a/doc/development/README.md b/doc/development/README.md
index 01dff0c2017..6121ddf3ed6 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -97,6 +97,7 @@ Complementary reads:
- [Issue types vs first-class types](issue_types.md)
- [Application limits](application_limits.md)
- [Redis guidelines](redis.md)
+- [Rails initializers](rails_initializers.md)
## Performance guides
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 77e5060720b..4e97e5961b6 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -187,4 +187,4 @@ NOTE: **Note:** Keep in mind that all runtimes should be measured against GitLab
|----|----|---|
| Regular migrations on `db/migrate` | `3 minutes` | A valid exception are index creation as this can take a long time. |
| Post migrations on `db/post_migrate` | `10 minutes` | |
-| Background migrations | --- | Since these are suitable for larger tables, it's not possible to set a precise timing guideline, however, any query must stay well below `10s` of execution time. |
+| Background migrations | --- | Since these are suitable for larger tables, it's not possible to set a precise timing guideline, however, any single query must stay below `1 second` execution time with cold caches. |
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index f3f46baa54f..3f202115b4c 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -432,10 +432,6 @@ default values if absolutely necessary. There is a RuboCop cop that will fail if
this method is used on some tables that are very large on GitLab.com, which
would cause other issues.
-For a small table (such as an empty one or one with less than `1,000` records),
-use `add_column` and `change_column_default` in a single-transaction migration,
-combining it with other operations that don't require `disable_ddl_transaction!`.
-
## Changing the column default
One might think that changing a default column with `change_column_default` is an
diff --git a/doc/development/rails_initializers.md b/doc/development/rails_initializers.md
new file mode 100644
index 00000000000..6473baf58d4
--- /dev/null
+++ b/doc/development/rails_initializers.md
@@ -0,0 +1,16 @@
+# Rails initializers
+
+By default, Rails loads Zeitwerk after the initializers in `config/initializers` are loaded.
+Autoloading before Zeitwerk is loaded is now deprecated but because we use a lot of autoloaded
+constants in our initializers, we had to move the loading of Zeitwerk earlier than these
+initializers.
+
+A side-effect of this is that in the initializers, `config.autoload_paths` is already frozen.
+
+To run an initializer before Zeitwerk is loaded, you need put them in `config/initializers_before_autoloader`.
+Ruby files in this folder are loaded in alphabetical order just like the default Rails initializers.
+
+Some examples where you would need to do this are:
+
+1. Modifying Rails' `config.autoload_paths`
+1. Changing configuration that Zeitwerk uses, e.g. inflections
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 8f64e9207b5..704dd89ede2 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -26,6 +26,8 @@ To change the default branch protection:
For more details, see [Protected branches](../../project/protected_branches.md).
+To change this setting for a specific group, see [Default branch protection for groups](../../group/index.md#changing-the-default-branch-protection-of-a-group)
+
## Default project creation protection
Project creation protection specifies which roles can create projects.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 6b76e070c41..cca82f6a4fb 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -181,6 +181,21 @@ of a group:
1. Give a different member **Owner** permissions.
1. Have the new owner sign in and remove **Owner** permissions from you.
+## Changing the default branch protection of a group
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7583) in GitLab 12.9.
+
+By default, every group inherits the branch protection set at the global level.
+
+To change this setting for a specific group:
+
+1. Go to the group's **{settings}** **Settings > General** page.
+1. Expand the **Permissions, LFS, 2FA** section.
+1. Select the desired option in the **Default branch protection** dropdown list.
+1. Click **Save changes**.
+
+To change this setting globally, see [Default branch protection](../admin_area/settings/visibility_and_access_controls.md#default-branch-protection).
+
## Add projects to a group
There are two different ways to add a new project to a group:
diff --git a/doc/user/project/issues/csv_import.md b/doc/user/project/issues/csv_import.md
index 56643dcee53..d67b135186f 100644
--- a/doc/user/project/issues/csv_import.md
+++ b/doc/user/project/issues/csv_import.md
@@ -3,7 +3,7 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23532) in GitLab 11.7.
Issues can be imported to a project by uploading a CSV file with the columns
-`title` and `description`, in that order.
+`title` and `description`.
The user uploading the CSV file will be set as the author of the imported issues.
@@ -31,9 +31,9 @@ to you once the import is complete.
When importing issues from a CSV file, it must be formatted in a certain way:
-- **header row:** CSV files must contain a header row where the first column header
- is `title` and the second is `description`. If additional columns are present, they
- will be ignored.
+- **header row:** CSV files must include the following headers:
+`title` and `description`. The case of the headers does not matter.
+- **columns:** Data from columns beyond `title` and `description` are not imported.
- **separators:** The column separator is automatically detected from the header row.
Supported separator characters are: commas (`,`), semicolons (`;`), and tabs (`\t`).
The row separator can be either `CRLF` or `LF`.
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index 0769e464d26..5cab13f001e 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -50,17 +50,13 @@ module API
user = find_user_from_sources
return unless user
+ # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
+ Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) if Feature.enabled?(:user_mode_in_session)
+
unless api_access_allowed?(user)
forbidden!(api_access_denied_message(user))
end
- # Set admin mode for API requests (if admin)
- if Feature.enabled?(:user_mode_in_session)
- current_user_mode = Gitlab::Auth::CurrentUserMode.new(user)
-
- current_user_mode.enable_sessionless_admin_mode!
- end
-
user
end
@@ -154,19 +150,13 @@ module API
end
class AdminModeMiddleware < ::Grape::Middleware::Base
- def initialize(app, **options)
- super
- end
+ def after
+ # Use a Grape middleware since the Grape `after` blocks might run
+ # before we are finished rendering the `Grape::Entity` classes
+ Gitlab::Auth::CurrentUserMode.reset_bypass_session! if Feature.enabled?(:user_mode_in_session)
- def call(env)
- if Feature.enabled?(:user_mode_in_session)
- session = {}
- Gitlab::Session.with_session(session) do
- app.call(env)
- end
- else
- app.call(env)
- end
+ # Explicit nil is needed or the api call return value will be overwritten
+ nil
end
end
end
diff --git a/lib/api/entities/group.rb b/lib/api/entities/group.rb
index ae5ee4784ed..10e10e52d9f 100644
--- a/lib/api/entities/group.rb
+++ b/lib/api/entities/group.rb
@@ -13,6 +13,7 @@ module API
expose :emails_disabled
expose :mentions_disabled
expose :lfs_enabled?, as: :lfs_enabled
+ expose :default_branch_protection
expose :avatar_url do |group, options|
group.avatar_url(only_path: false)
end
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index e0fea4c7c96..25701ff683d 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -21,6 +21,7 @@ module API
optional :mentions_disabled, type: Boolean, desc: 'Disable a group from getting mentioned'
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
+ optional :default_branch_protection, type: Integer, values: ::Gitlab::Access.protection_values, desc: 'Determine if developers can push to master'
end
params :optional_params_ee do
diff --git a/lib/gitlab/access/branch_protection.rb b/lib/gitlab/access/branch_protection.rb
index f039e5c011f..339a99eb068 100644
--- a/lib/gitlab/access/branch_protection.rb
+++ b/lib/gitlab/access/branch_protection.rb
@@ -37,6 +37,10 @@ module Gitlab
def developer_can_merge?
level == PROTECTION_DEV_CAN_MERGE
end
+
+ def fully_protected?
+ level == PROTECTION_FULL
+ end
end
end
end
diff --git a/lib/gitlab/auth/current_user_mode.rb b/lib/gitlab/auth/current_user_mode.rb
index 1ef95c03cfc..06ae4d81870 100644
--- a/lib/gitlab/auth/current_user_mode.rb
+++ b/lib/gitlab/auth/current_user_mode.rb
@@ -23,15 +23,26 @@ module Gitlab
class << self
# Admin mode activation requires storing a flag in the user session. Using this
- # method when scheduling jobs in Sidekiq will bypass the session check for a
- # user that was already in admin mode
+ # method when scheduling jobs in sessionless environments (e.g. Sidekiq, API)
+ # will bypass the session check for a user that was already in admin mode
+ #
+ # If passed a block, it will surround the block execution and reset the session
+ # bypass at the end; otherwise use manually '.reset_bypass_session!'
def bypass_session!(admin_id)
Gitlab::SafeRequestStore[CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY] = admin_id
Gitlab::AppLogger.debug("Bypassing session in admin mode for: #{admin_id}")
- yield
- ensure
+ if block_given?
+ begin
+ yield
+ ensure
+ reset_bypass_session!
+ end
+ end
+ end
+
+ def reset_bypass_session!
Gitlab::SafeRequestStore.delete(CURRENT_REQUEST_BYPASS_SESSION_ADMIN_ID_RS_KEY)
end
@@ -90,10 +101,6 @@ module Gitlab
current_session_data[ADMIN_MODE_START_TIME_KEY] = Time.now
end
- def enable_sessionless_admin_mode!
- request_admin_mode! && enable_admin_mode!(skip_password_validation: true)
- end
-
def disable_admin_mode!
return unless user&.admin?
diff --git a/lib/gitlab/graphql/connections.rb b/lib/gitlab/graphql/connections.rb
index 08d5cd0b72e..0c0bfe5a458 100644
--- a/lib/gitlab/graphql/connections.rb
+++ b/lib/gitlab/graphql/connections.rb
@@ -16,6 +16,10 @@ module Gitlab
Gitlab::Graphql::ExternallyPaginatedArray,
Gitlab::Graphql::Connections::ExternallyPaginatedArrayConnection
)
+ GraphQL::Relay::BaseConnection.register_connection_implementation(
+ Gitlab::Graphql::Pagination::Relations::OffsetActiveRecordRelation,
+ Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection
+ )
end
end
end
diff --git a/lib/gitlab/graphql/pagination/offset_active_record_relation_connection.rb b/lib/gitlab/graphql/pagination/offset_active_record_relation_connection.rb
new file mode 100644
index 00000000000..c852fbf0ab8
--- /dev/null
+++ b/lib/gitlab/graphql/pagination/offset_active_record_relation_connection.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+# We use the Keyset / Stable cursor connection by default for ActiveRecord::Relation.
+# However, there are times when that may not be powerful enough (yet), and we
+# want to use standard offset pagination.
+module Gitlab
+ module Graphql
+ module Pagination
+ class OffsetActiveRecordRelationConnection < GraphQL::Relay::RelationConnection
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/pagination/relations/offset_active_record_relation.rb b/lib/gitlab/graphql/pagination/relations/offset_active_record_relation.rb
new file mode 100644
index 00000000000..2e5a0d66d4e
--- /dev/null
+++ b/lib/gitlab/graphql/pagination/relations/offset_active_record_relation.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module Pagination
+ module Relations
+ class OffsetActiveRecordRelation < ::ActiveRecord::Relation
+ end
+ end
+ end
+ end
+end
diff --git a/package.json b/package.json
index 852f9cfcc87..645f687186d 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "^1.5.5",
"@gitlab/svgs": "^1.104.0",
- "@gitlab/ui": "^9.18.0",
+ "@gitlab/ui": "^9.18.2",
"@gitlab/visual-review-tools": "1.5.1",
"@sentry/browser": "^5.10.2",
"@sourcegraph/code-host-integration": "0.0.30",
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index 95b0295622a..a54dadb8d85 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -17,10 +17,10 @@ gitlab:
resources:
requests:
cpu: 1200m
- memory: 240M
+ memory: 245M
limits:
cpu: 1800m
- memory: 360M
+ memory: 367M
persistence:
size: 10G
gitlab-exporter:
@@ -51,11 +51,11 @@ gitlab:
sidekiq:
resources:
requests:
- cpu: 650m
- memory: 1018M
+ cpu: 855m
+ memory: 1071M
limits:
- cpu: 975m
- memory: 1527M
+ cpu: 1282m
+ memory: 1606M
hpa:
targetAverageValue: 650m
task-runner:
@@ -69,11 +69,11 @@ gitlab:
unicorn:
resources:
requests:
- cpu: 525m
- memory: 1711M
+ cpu: 746m
+ memory: 1873M
limits:
- cpu: 787m
- memory: 2566M
+ cpu: 1119m
+ memory: 2809M
deployment:
readinessProbe:
initialDelaySeconds: 5 # Default is 0
@@ -140,10 +140,10 @@ postgresql:
enabled: false
resources:
requests:
- cpu: 300m
+ cpu: 347m
memory: 250M
limits:
- cpu: 450m
+ cpu: 520m
memory: 375M
prometheus:
install: false
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 1c58c2b5c97..11c70d3aeca 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -411,6 +411,13 @@ describe GroupsController do
expect(group.reload.project_creation_level).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
+ it 'updates the default_branch_protection successfully' do
+ post :update, params: { id: group.to_param, group: { default_branch_protection: ::Gitlab::Access::PROTECTION_DEV_CAN_MERGE } }
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(group.reload.default_branch_protection).to eq(::Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ end
+
context 'when a project inside the group has container repositories' do
before do
stub_container_registry_config(enabled: true)
diff --git a/spec/fixtures/csv_gitlab_export.csv b/spec/fixtures/csv_gitlab_export.csv
new file mode 100644
index 00000000000..65422509eef
--- /dev/null
+++ b/spec/fixtures/csv_gitlab_export.csv
@@ -0,0 +1,5 @@
+Issue ID,URL,Title,State,Description,Author,Author Username,Assignee,Assignee Username,Confidential,Locked,Due Date,Created At (UTC),Updated At (UTC),Closed At (UTC),Milestone,Weight,Labels,Time Estimate,Time Spent,Epic ID,Epic Title
+1,http://localhost:3000/jashkenas/underscore/issues/1,Title,Open,,Elva Jerde,jamel,Tierra Effertz,aurora_hahn,No,No,,2020-01-17 10:36:26,2020-02-19 10:36:26,,v1.0,,"Brene,Cutlass,Escort,GVM",0,0,,
+3,http://localhost:3000/jashkenas/underscore/issues/3,Nihil impedit neque quos totam ut aut enim cupiditate doloribus molestiae.,Open,Omnis aliquid sint laudantium quam.,Marybeth Goodwin,rocio.blanda,Annemarie Von,reynalda_howe,No,No,,2020-01-23 10:36:26,2020-02-19 10:36:27,,v1.0,,"Brene,Cutlass,Escort,GVM",0,0,,
+34,http://localhost:3000/jashkenas/underscore/issues/34,Dismiss Cipher with no integrity,Open,,Marybeth Goodwin,rocio.blanda,"","",No,No,,2020-02-19 10:38:49,2020-02-19 10:38:49,,,,,0,0,,
+35,http://localhost:3000/jashkenas/underscore/issues/35,Test Title,Open,Test Description,Marybeth Goodwin,rocio.blanda,"","",No,No,,2020-02-19 10:38:49,2020-02-19 10:38:49,,,,,0,0,,
diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb
index 2ec477fc494..d0eb0475879 100644
--- a/spec/graphql/gitlab_schema_spec.rb
+++ b/spec/graphql/gitlab_schema_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
describe GitlabSchema do
+ let_it_be(:implementations) { GraphQL::Relay::BaseConnection::CONNECTION_IMPLEMENTATIONS }
let(:user) { build :user }
it 'uses batch loading' do
@@ -33,12 +34,30 @@ describe GitlabSchema do
expect(described_class.query).to eq(::Types::QueryType.to_graphql)
end
- it 'paginates active record relations using `Gitlab::Graphql::Connections::KeysetConnection`' do
- connection = GraphQL::Relay::BaseConnection::CONNECTION_IMPLEMENTATIONS[ActiveRecord::Relation.name]
+ it 'paginates active record relations using `Connections::Keyset::Connection`' do
+ connection = implementations[ActiveRecord::Relation.name]
expect(connection).to eq(Gitlab::Graphql::Connections::Keyset::Connection)
end
+ it 'paginates ExternallyPaginatedArray using `Connections::ExternallyPaginatedArrayConnection`' do
+ connection = implementations[Gitlab::Graphql::ExternallyPaginatedArray.name]
+
+ expect(connection).to eq(Gitlab::Graphql::Connections::ExternallyPaginatedArrayConnection)
+ end
+
+ it 'paginates FilterableArray using `Connections::FilterableArrayConnection`' do
+ connection = implementations[Gitlab::Graphql::FilterableArray.name]
+
+ expect(connection).to eq(Gitlab::Graphql::Connections::FilterableArrayConnection)
+ end
+
+ it 'paginates OffsetActiveRecordRelation using `Pagination::OffsetActiveRecordRelationConnection`' do
+ connection = implementations[Gitlab::Graphql::Pagination::Relations::OffsetActiveRecordRelation.name]
+
+ expect(connection).to eq(Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
+ end
+
describe '.execute' do
context 'for different types of users' do
context 'when no context' do
diff --git a/spec/lib/gitlab/access/branch_protection_spec.rb b/spec/lib/gitlab/access/branch_protection_spec.rb
index 7f2979e8e28..e4b763357c4 100644
--- a/spec/lib/gitlab/access/branch_protection_spec.rb
+++ b/spec/lib/gitlab/access/branch_protection_spec.rb
@@ -51,4 +51,21 @@ describe Gitlab::Access::BranchProtection do
end
end
end
+
+ describe '#fully_protected?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:level, :result) do
+ Gitlab::Access::PROTECTION_NONE | false
+ Gitlab::Access::PROTECTION_DEV_CAN_PUSH | false
+ Gitlab::Access::PROTECTION_DEV_CAN_MERGE | false
+ Gitlab::Access::PROTECTION_FULL | true
+ end
+
+ with_them do
+ it do
+ expect(described_class.new(level).fully_protected?).to eq(result)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/auth/current_user_mode_spec.rb b/spec/lib/gitlab/auth/current_user_mode_spec.rb
index 7c2fdac6c25..2b910fac155 100644
--- a/spec/lib/gitlab/auth/current_user_mode_spec.rb
+++ b/spec/lib/gitlab/auth/current_user_mode_spec.rb
@@ -3,294 +3,330 @@
require 'spec_helper'
describe Gitlab::Auth::CurrentUserMode, :do_not_mock_admin_mode, :request_store do
- include_context 'custom session'
-
let(:user) { build_stubbed(:user) }
subject { described_class.new(user) }
- before do
- allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session])
- end
-
- shared_examples 'admin mode cannot be enabled' do
- it 'is false by default' do
- expect(subject.admin_mode?).to be(false)
- end
-
- it 'cannot be enabled with a valid password' do
- subject.enable_admin_mode!(password: user.password)
-
- expect(subject.admin_mode?).to be(false)
- end
-
- it 'cannot be enabled with an invalid password' do
- subject.enable_admin_mode!(password: nil)
-
- expect(subject.admin_mode?).to be(false)
- end
-
- it 'cannot be enabled with empty params' do
- subject.enable_admin_mode!
+ context 'when session is available' do
+ include_context 'custom session'
- expect(subject.admin_mode?).to be(false)
+ before do
+ allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session])
end
- it 'disable has no effect' do
- subject.enable_admin_mode!
- subject.disable_admin_mode!
-
- expect(subject.admin_mode?).to be(false)
- end
+ shared_examples 'admin mode cannot be enabled' do
+ it 'is false by default' do
+ expect(subject.admin_mode?).to be(false)
+ end
- context 'skipping password validation' do
it 'cannot be enabled with a valid password' do
- subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
+ subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
- subject.enable_admin_mode!(skip_password_validation: true)
+ subject.enable_admin_mode!(password: nil)
expect(subject.admin_mode?).to be(false)
end
- end
- end
- describe '#admin_mode?' do
- context 'when the user is a regular user' do
- it_behaves_like 'admin mode cannot be enabled'
+ it 'cannot be enabled with empty params' do
+ subject.enable_admin_mode!
- context 'bypassing session' do
- it_behaves_like 'admin mode cannot be enabled' do
- around do |example|
- described_class.bypass_session!(user.id) { example.run }
- end
- end
+ expect(subject.admin_mode?).to be(false)
end
- end
-
- context 'when the user is an admin' do
- let(:user) { build_stubbed(:user, :admin) }
- context 'when admin mode not requested' do
- it 'is false by default' do
- expect(subject.admin_mode?).to be(false)
- end
-
- it 'raises exception if we try to enable it' do
- expect do
- subject.enable_admin_mode!(password: user.password)
- end.to raise_error(::Gitlab::Auth::CurrentUserMode::NotRequestedError)
+ it 'disable has no effect' do
+ subject.enable_admin_mode!
+ subject.disable_admin_mode!
- expect(subject.admin_mode?).to be(false)
- end
+ expect(subject.admin_mode?).to be(false)
end
- context 'when admin mode requested first' do
- before do
- subject.request_admin_mode!
- end
+ context 'skipping password validation' do
+ it 'cannot be enabled with a valid password' do
+ subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
- it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
- subject.enable_admin_mode!(password: nil)
+ subject.enable_admin_mode!(skip_password_validation: true)
expect(subject.admin_mode?).to be(false)
end
+ end
+ end
- it 'can be enabled with a valid password' do
- subject.enable_admin_mode!(password: user.password)
+ describe '#admin_mode?' do
+ context 'when the user is a regular user' do
+ it_behaves_like 'admin mode cannot be enabled'
- expect(subject.admin_mode?).to be(true)
+ context 'bypassing session' do
+ it_behaves_like 'admin mode cannot be enabled' do
+ around do |example|
+ described_class.bypass_session!(user.id) { example.run }
+ end
+ end
end
+ end
- it 'can be disabled' do
- subject.enable_admin_mode!(password: user.password)
- subject.disable_admin_mode!
+ context 'when the user is an admin' do
+ let(:user) { build_stubbed(:user, :admin) }
- expect(subject.admin_mode?).to be(false)
+ context 'when admin mode not requested' do
+ it 'is false by default' do
+ expect(subject.admin_mode?).to be(false)
+ end
+
+ it 'raises exception if we try to enable it' do
+ expect do
+ subject.enable_admin_mode!(password: user.password)
+ end.to raise_error(::Gitlab::Auth::CurrentUserMode::NotRequestedError)
+
+ expect(subject.admin_mode?).to be(false)
+ end
end
- it 'will expire in the future' do
- subject.enable_admin_mode!(password: user.password)
- expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
+ context 'when admin mode requested first' do
+ before do
+ subject.request_admin_mode!
+ end
- Timecop.freeze(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
- # in the future this will be a new request, simulate by clearing the RequestStore
- Gitlab::SafeRequestStore.clear!
+ it 'is false by default' do
+ expect(subject.admin_mode?).to be(false)
+ end
+
+ it 'cannot be enabled with an invalid password' do
+ subject.enable_admin_mode!(password: nil)
- expect(subject.admin_mode?).to be(false), 'admin mode did not expire in the future'
+ expect(subject.admin_mode?).to be(false)
end
- end
- context 'skipping password validation' do
it 'can be enabled with a valid password' do
- subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
+ subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
- it 'can be enabled with an invalid password' do
- subject.enable_admin_mode!(skip_password_validation: true)
+ it 'can be disabled' do
+ subject.enable_admin_mode!(password: user.password)
+ subject.disable_admin_mode!
- expect(subject.admin_mode?).to be(true)
+ expect(subject.admin_mode?).to be(false)
end
- end
- context 'with two independent sessions' do
- let(:another_session) { {} }
- let(:another_subject) { described_class.new(user) }
+ it 'will expire in the future' do
+ subject.enable_admin_mode!(password: user.password)
+ expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
- before do
- allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session, another_session])
+ Timecop.freeze(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
+ # in the future this will be a new request, simulate by clearing the RequestStore
+ Gitlab::SafeRequestStore.clear!
+
+ expect(subject.admin_mode?).to be(false), 'admin mode did not expire in the future'
+ end
end
- it 'can be enabled in one and seen in the other' do
- Gitlab::Session.with_session(another_session) do
- another_subject.request_admin_mode!
- another_subject.enable_admin_mode!(password: user.password)
+ context 'skipping password validation' do
+ it 'can be enabled with a valid password' do
+ subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
+
+ expect(subject.admin_mode?).to be(true)
end
- expect(subject.admin_mode?).to be(true)
+ it 'can be enabled with an invalid password' do
+ subject.enable_admin_mode!(skip_password_validation: true)
+
+ expect(subject.admin_mode?).to be(true)
+ end
end
- end
- end
- context 'bypassing session' do
- it 'is active by default' do
- described_class.bypass_session!(user.id) do
- expect(subject.admin_mode?).to be(true)
+ context 'with two independent sessions' do
+ let(:another_session) { {} }
+ let(:another_subject) { described_class.new(user) }
+
+ before do
+ allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session, another_session])
+ end
+
+ it 'can be enabled in one and seen in the other' do
+ Gitlab::Session.with_session(another_session) do
+ another_subject.request_admin_mode!
+ another_subject.enable_admin_mode!(password: user.password)
+ end
+
+ expect(subject.admin_mode?).to be(true)
+ end
end
end
- it 'enable has no effect' do
- described_class.bypass_session!(user.id) do
- subject.request_admin_mode!
- subject.enable_admin_mode!(password: user.password)
+ context 'bypassing session' do
+ it 'is active by default' do
+ described_class.bypass_session!(user.id) do
+ expect(subject.admin_mode?).to be(true)
+ end
+ end
- expect(subject.admin_mode?).to be(true)
+ it 'enable has no effect' do
+ described_class.bypass_session!(user.id) do
+ subject.request_admin_mode!
+ subject.enable_admin_mode!(password: user.password)
+
+ expect(subject.admin_mode?).to be(true)
+ end
end
- end
- it 'disable has no effect' do
- described_class.bypass_session!(user.id) do
- subject.disable_admin_mode!
+ it 'disable has no effect' do
+ described_class.bypass_session!(user.id) do
+ subject.disable_admin_mode!
- expect(subject.admin_mode?).to be(true)
+ expect(subject.admin_mode?).to be(true)
+ end
end
end
end
end
- end
- describe '#enable_admin_mode!' do
- let(:user) { build_stubbed(:user, :admin) }
+ describe '#enable_admin_mode!' do
+ let(:user) { build_stubbed(:user, :admin) }
- it 'creates a timestamp in the session' do
- subject.request_admin_mode!
- subject.enable_admin_mode!(password: user.password)
+ it 'creates a timestamp in the session' do
+ subject.request_admin_mode!
+ subject.enable_admin_mode!(password: user.password)
- expect(session).to include(expected_session_entry(be_within(1.second).of Time.now))
+ expect(session).to include(expected_session_entry(be_within(1.second).of Time.now))
+ end
end
- end
- describe '#enable_sessionless_admin_mode!' do
- let(:user) { build_stubbed(:user, :admin) }
+ describe '#disable_admin_mode!' do
+ let(:user) { build_stubbed(:user, :admin) }
- it 'enabled admin mode without password' do
- subject.enable_sessionless_admin_mode!
+ it 'sets the session timestamp to nil' do
+ subject.request_admin_mode!
+ subject.disable_admin_mode!
- expect(subject.admin_mode?).to be(true)
+ expect(session).to include(expected_session_entry(be_nil))
+ end
end
- end
- describe '#disable_admin_mode!' do
- let(:user) { build_stubbed(:user, :admin) }
+ describe '.with_current_request_admin_mode' do
+ context 'with a regular user' do
+ it 'user is not available inside nor outside the yielded block' do
+ described_class.with_current_admin(user) do
+ expect(described_class.current_admin).to be_nil
+ end
- it 'sets the session timestamp to nil' do
- subject.request_admin_mode!
- subject.disable_admin_mode!
+ expect(described_class.bypass_session_admin_id).to be_nil
+ end
+ end
- expect(session).to include(expected_session_entry(be_nil))
- end
- end
+ context 'with an admin user' do
+ let(:user) { build_stubbed(:user, :admin) }
- describe '.bypass_session!' do
- context 'with a regular user' do
- it 'admin mode is false' do
- described_class.bypass_session!(user.id) do
- expect(subject.admin_mode?).to be(false)
- expect(described_class.bypass_session_admin_id).to be(user.id)
+ context 'admin mode is disabled' do
+ it 'user is not available inside nor outside the yielded block' do
+ described_class.with_current_admin(user) do
+ expect(described_class.current_admin).to be_nil
+ end
+
+ expect(described_class.bypass_session_admin_id).to be_nil
+ end
end
- expect(described_class.bypass_session_admin_id).to be_nil
- end
- end
+ context 'admin mode is enabled' do
+ before do
+ subject.request_admin_mode!
+ subject.enable_admin_mode!(password: user.password)
+ end
- context 'with an admin user' do
- let(:user) { build_stubbed(:user, :admin) }
+ it 'user is available only inside the yielded block' do
+ described_class.with_current_admin(user) do
+ expect(described_class.current_admin).to be(user)
+ end
- it 'admin mode is true' do
- described_class.bypass_session!(user.id) do
- expect(subject.admin_mode?).to be(true)
- expect(described_class.bypass_session_admin_id).to be(user.id)
+ expect(described_class.current_admin).to be_nil
+ end
end
-
- expect(described_class.bypass_session_admin_id).to be_nil
end
end
- end
- describe '.with_current_request_admin_mode' do
- context 'with a regular user' do
- it 'user is not available inside nor outside the yielded block' do
- described_class.with_current_admin(user) do
- expect(described_class.current_admin).to be_nil
- end
+ def expected_session_entry(value_matcher)
+ {
+ Gitlab::Auth::CurrentUserMode::SESSION_STORE_KEY => a_hash_including(
+ Gitlab::Auth::CurrentUserMode::ADMIN_MODE_START_TIME_KEY => value_matcher)
+ }
+ end
+ end
- expect(described_class.bypass_session_admin_id).to be_nil
+ context 'when no session available' do
+ around do |example|
+ Gitlab::Session.with_session(nil) do
+ example.run
end
end
- context 'with an admin user' do
- let(:user) { build_stubbed(:user, :admin) }
+ describe '.bypass_session!' do
+ context 'when providing a block' do
+ context 'with a regular user' do
+ it 'admin mode is false' do
+ described_class.bypass_session!(user.id) do
+ expect(Gitlab::Session.current).to be_nil
+ expect(subject.admin_mode?).to be(false)
+ expect(described_class.bypass_session_admin_id).to be(user.id)
+ end
- context 'admin mode is disabled' do
- it 'user is not available inside nor outside the yielded block' do
- described_class.with_current_admin(user) do
- expect(described_class.current_admin).to be_nil
+ expect(described_class.bypass_session_admin_id).to be_nil
end
+ end
- expect(described_class.bypass_session_admin_id).to be_nil
+ context 'with an admin user' do
+ let(:user) { build_stubbed(:user, :admin) }
+
+ it 'admin mode is true' do
+ described_class.bypass_session!(user.id) do
+ expect(Gitlab::Session.current).to be_nil
+ expect(subject.admin_mode?).to be(true)
+ expect(described_class.bypass_session_admin_id).to be(user.id)
+ end
+
+ expect(described_class.bypass_session_admin_id).to be_nil
+ end
end
end
- context 'admin mode is enabled' do
- before do
- subject.request_admin_mode!
- subject.enable_admin_mode!(password: user.password)
- end
+ context 'when not providing a block' do
+ context 'with a regular user' do
+ it 'admin mode is false' do
+ described_class.bypass_session!(user.id)
- it 'user is available only inside the yielded block' do
- described_class.with_current_admin(user) do
- expect(described_class.current_admin).to be(user)
+ expect(Gitlab::Session.current).to be_nil
+ expect(subject.admin_mode?).to be(false)
+ expect(described_class.bypass_session_admin_id).to be(user.id)
+
+ described_class.reset_bypass_session!
+
+ expect(described_class.bypass_session_admin_id).to be_nil
end
+ end
- expect(described_class.current_admin).to be_nil
+ context 'with an admin user' do
+ let(:user) { build_stubbed(:user, :admin) }
+
+ it 'admin mode is true' do
+ described_class.bypass_session!(user.id)
+
+ expect(Gitlab::Session.current).to be_nil
+ expect(subject.admin_mode?).to be(true)
+ expect(described_class.bypass_session_admin_id).to be(user.id)
+
+ described_class.reset_bypass_session!
+
+ expect(described_class.bypass_session_admin_id).to be_nil
+ end
end
end
end
end
-
- def expected_session_entry(value_matcher)
- {
- Gitlab::Auth::CurrentUserMode::SESSION_STORE_KEY => a_hash_including(
- Gitlab::Auth::CurrentUserMode::ADMIN_MODE_START_TIME_KEY => value_matcher)
- }
- end
end
diff --git a/spec/lib/gitlab/graphql/pagination/offset_active_record_relation_connection_spec.rb b/spec/lib/gitlab/graphql/pagination/offset_active_record_relation_connection_spec.rb
new file mode 100644
index 00000000000..2269b4def82
--- /dev/null
+++ b/spec/lib/gitlab/graphql/pagination/offset_active_record_relation_connection_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection do
+ it 'subclasses from GraphQL::Relay::RelationConnection' do
+ expect(described_class.superclass).to eq GraphQL::Relay::RelationConnection
+ end
+end
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 2f4ab2e71db..8d13f377677 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -46,32 +46,27 @@ describe Gitlab::UserAccess do
expect(project_access.can_push_to_branch?('master')).to be_truthy
end
- it 'returns false if user is developer and project is fully protected' do
- empty_project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
-
- expect(project_access.can_push_to_branch?('master')).to be_falsey
- end
-
- it 'returns false if user is developer and it is not allowed to push new commits but can merge into branch' do
- empty_project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
-
- expect(project_access.can_push_to_branch?('master')).to be_falsey
- end
-
- it 'returns true if user is developer and project is unprotected' do
- empty_project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
-
- expect(project_access.can_push_to_branch?('master')).to be_truthy
- end
-
- it 'returns true if user is developer and project grants developers permission' do
- empty_project.add_developer(user)
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
-
- expect(project_access.can_push_to_branch?('master')).to be_truthy
+ context 'when the user is a developer' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ empty_project.add_developer(user)
+ end
+
+ where(:default_branch_protection_level, :result) do
+ Gitlab::Access::PROTECTION_NONE | true
+ Gitlab::Access::PROTECTION_DEV_CAN_PUSH | true
+ Gitlab::Access::PROTECTION_DEV_CAN_MERGE | false
+ Gitlab::Access::PROTECTION_FULL | false
+ end
+
+ with_them do
+ it do
+ expect(empty_project.namespace).to receive(:default_branch_protection).and_return(default_branch_protection_level).at_least(:once)
+
+ expect(project_access.can_push_to_branch?('master')).to eq(result)
+ end
+ end
end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index ab7e12cd43c..86dfa586862 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -520,6 +520,21 @@ describe Deployment do
end
end
+ describe '#create_ref' do
+ let(:deployment) { build(:deployment) }
+
+ subject { deployment.create_ref }
+
+ it 'creates a ref using the sha' do
+ expect(deployment.project.repository).to receive(:create_ref).with(
+ deployment.sha,
+ "refs/environments/#{deployment.environment.name}/deployments/#{deployment.iid}"
+ )
+
+ subject
+ end
+ end
+
describe '#playable_build' do
subject { deployment.playable_build }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 48cabd4301c..03aef7aea5c 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -325,26 +325,6 @@ describe Environment, :use_clean_rails_memory_store_caching do
end
end
- describe '#first_deployment_for' do
- let(:project) { create(:project, :repository) }
- let!(:deployment) { create(:deployment, :succeed, environment: environment, ref: commit.parent.id) }
- let!(:deployment1) { create(:deployment, :succeed, environment: environment, ref: commit.id) }
- let(:head_commit) { project.commit }
- let(:commit) { project.commit.parent }
-
- it 'returns deployment id for the environment', :sidekiq_might_not_need_inline do
- expect(environment.first_deployment_for(commit.id)).to eq deployment1
- end
-
- it 'return nil when no deployment is found' do
- expect(environment.first_deployment_for(head_commit.id)).to eq nil
- end
-
- it 'returns a UTF-8 ref', :sidekiq_might_not_need_inline do
- expect(environment.first_deployment_for(commit.id).ref).to be_utf8
- end
- end
-
describe '#environment_type' do
subject { environment.environment_type }
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 54e54366c5a..276fbc2cb54 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -531,6 +531,41 @@ describe Namespace do
end
end
+ describe "#default_branch_protection" do
+ let(:namespace) { create(:namespace) }
+ let(:default_branch_protection) { nil }
+ let(:group) { create(:group, default_branch_protection: default_branch_protection) }
+
+ before do
+ stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ end
+
+ context 'for a namespace' do
+ # Unlike a group, the settings of a namespace cannot be altered
+ # via the UI or the API.
+
+ it 'returns the instance level setting' do
+ expect(namespace.default_branch_protection).to eq(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ end
+ end
+
+ context 'for a group' do
+ context 'that has not altered the default value' do
+ it 'returns the instance level setting' do
+ expect(group.default_branch_protection).to eq(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ end
+ end
+
+ context 'that has altered the default value' do
+ let(:default_branch_protection) { Gitlab::Access::PROTECTION_FULL }
+
+ it 'returns the group level setting' do
+ expect(group.default_branch_protection).to eq(default_branch_protection)
+ end
+ end
+ end
+ end
+
describe '#self_and_hierarchy' do
let!(:group) { create(:group, path: 'git_lab') }
let!(:nested_group) { create(:group, parent: group) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 2b4a832634f..4885d4b63ff 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1623,6 +1623,29 @@ describe Project do
end
end
+ describe '#default_branch_protected?' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:project) { create(:project) }
+
+ subject { project.default_branch_protected? }
+
+ where(:default_branch_protection_level, :result) do
+ Gitlab::Access::PROTECTION_NONE | false
+ Gitlab::Access::PROTECTION_DEV_CAN_PUSH | false
+ Gitlab::Access::PROTECTION_DEV_CAN_MERGE | true
+ Gitlab::Access::PROTECTION_FULL | true
+ end
+
+ with_them do
+ before do
+ expect(project.namespace).to receive(:default_branch_protection).and_return(default_branch_protection_level)
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
+
describe '#pages_url' do
let(:group) { create(:group, name: group_name) }
let(:project) { create(:project, namespace: group, name: project_name) }
@@ -4576,7 +4599,7 @@ describe Project do
end
it 'does not protect when branch protection is disabled' do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_NONE)
project.after_import
@@ -4584,7 +4607,7 @@ describe Project do
end
it "gives developer access to push when branch protection is set to 'developers can push'" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
project.after_import
@@ -4594,7 +4617,7 @@ describe Project do
end
it "gives developer access to merge when branch protection is set to 'developers can merge'" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
project.after_import
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index 7f8a60dafa8..30fce1cd5c4 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -164,31 +164,45 @@ describe ProtectedBranch do
end
end
- context "new project" do
- let(:project) { create(:project) }
+ context 'new project' do
+ using RSpec::Parameterized::TableSyntax
- it 'returns false when default_protected_branch is unprotected' do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ let(:project) { create(:project) }
- expect(described_class.protected?(project, 'master')).to be false
- end
+ context 'when the group has set their own default_branch_protection level' do
+ where(:default_branch_protection_level, :result) do
+ Gitlab::Access::PROTECTION_NONE | false
+ Gitlab::Access::PROTECTION_DEV_CAN_PUSH | false
+ Gitlab::Access::PROTECTION_DEV_CAN_MERGE | true
+ Gitlab::Access::PROTECTION_FULL | true
+ end
- it 'returns false when default_protected_branch lets developers push' do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+ with_them do
+ it 'protects the default branch based on the default branch protection setting of the group' do
+ expect(project.namespace).to receive(:default_branch_protection).and_return(default_branch_protection_level)
- expect(described_class.protected?(project, 'master')).to be false
+ expect(described_class.protected?(project, 'master')).to eq(result)
+ end
+ end
end
- it 'returns true when default_branch_protection does not let developers push but let developer merge branches' do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
-
- expect(described_class.protected?(project, 'master')).to be true
- end
+ context 'when the group has not set their own default_branch_protection level' do
+ where(:default_branch_protection_level, :result) do
+ Gitlab::Access::PROTECTION_NONE | false
+ Gitlab::Access::PROTECTION_DEV_CAN_PUSH | false
+ Gitlab::Access::PROTECTION_DEV_CAN_MERGE | true
+ Gitlab::Access::PROTECTION_FULL | true
+ end
- it 'returns true when default_branch_protection is in full protection' do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
+ with_them do
+ before do
+ stub_application_setting(default_branch_protection: default_branch_protection_level)
+ end
- expect(described_class.protected?(project, 'master')).to be true
+ it 'protects the default branch based on the instance level default branch protection setting' do
+ expect(described_class.protected?(project, 'master')).to eq(result)
+ end
+ end
end
end
end
diff --git a/spec/requests/api/api_guard/admin_mode_middleware_spec.rb b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
new file mode 100644
index 00000000000..8973afe6570
--- /dev/null
+++ b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::APIGuard::AdminModeMiddleware, :do_not_mock_admin_mode, :request_store do
+ let(:user) { create(:admin) }
+
+ it 'is loaded' do
+ expect(API::API.middleware).to include([:use, described_class])
+ end
+
+ context 'when there is an exception in the api call' do
+ let(:app) do
+ Class.new(API::API) do
+ get 'willfail' do
+ raise StandardError.new('oh noes!')
+ end
+ end
+ end
+
+ it 'resets admin mode' do
+ Gitlab::Auth::CurrentUserMode.bypass_session!(user.id)
+
+ expect(Gitlab::Auth::CurrentUserMode.bypass_session_admin_id).to be(user.id)
+ expect(Gitlab::Auth::CurrentUserMode).to receive(:reset_bypass_session!).and_call_original
+
+ get api('/willfail')
+
+ expect(response.status).to eq(500)
+ expect(response.body).to include('oh noes!')
+
+ expect(Gitlab::Auth::CurrentUserMode.bypass_session_admin_id).to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/group_query_spec.rb b/spec/requests/api/graphql/group_query_spec.rb
index 6e2663fb090..a38d1857076 100644
--- a/spec/requests/api/graphql/group_query_spec.rb
+++ b/spec/requests/api/graphql/group_query_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
# Based on spec/requests/api/groups_spec.rb
# Should follow closely in order to ensure all situations are covered
-describe 'getting group information' do
+describe 'getting group information', :do_not_mock_admin_mode do
include GraphqlHelpers
include UploadHelpers
diff --git a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
index f80a3401134..05e3f7e6806 100644
--- a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Mark snippet as spam' do
+describe 'Mark snippet as spam', :do_not_mock_admin_mode do
include GraphqlHelpers
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index e8499246840..fb564bb398b 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -545,7 +545,8 @@ describe API::Groups do
name: new_group_name,
request_access_enabled: true,
project_creation_level: "noone",
- subgroup_creation_level: "maintainer"
+ subgroup_creation_level: "maintainer",
+ default_branch_protection: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
}
expect(response).to have_gitlab_http_status(:ok)
@@ -566,6 +567,7 @@ describe API::Groups do
expect(json_response['projects'].length).to eq(2)
expect(json_response['shared_projects']).to be_an Array
expect(json_response['shared_projects'].length).to eq(0)
+ expect(json_response['default_branch_protection']).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
it 'returns 404 for a non existing group' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 12ac601c013..5a302f0528e 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::Users do
+describe API::Users, :do_not_mock_admin_mode do
let(:user) { create(:user, username: 'user.with.dot') }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
diff --git a/spec/services/deployments/after_create_service_spec.rb b/spec/services/deployments/after_create_service_spec.rb
index 51c6de2c0b9..605700c73b2 100644
--- a/spec/services/deployments/after_create_service_spec.rb
+++ b/spec/services/deployments/after_create_service_spec.rb
@@ -49,7 +49,7 @@ describe Deployments::AfterCreateService do
it 'creates ref' do
expect_any_instance_of(Repository)
.to receive(:create_ref)
- .with(deployment.ref, deployment.send(:ref_path))
+ .with(deployment.sha, deployment.send(:ref_path))
service.execute
end
diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb
index 8b4f45010ed..d7357cf4d0b 100644
--- a/spec/services/git/branch_push_service_spec.rb
+++ b/spec/services/git/branch_push_service_spec.rb
@@ -186,7 +186,7 @@ describe Git::BranchPushService, services: true do
end
it "when pushing a branch for the first time with default branch protection disabled" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_NONE)
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
@@ -195,7 +195,7 @@ describe Git::BranchPushService, services: true do
end
it "when pushing a branch for the first time with default branch protection set to 'developers can push'" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
@@ -208,7 +208,7 @@ describe Git::BranchPushService, services: true do
end
it "when pushing a branch for the first time with an existing branch permission configured" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
create(:protected_branch, :no_one_can_push, :developers_can_merge, project: project, name: 'master')
expect(project).to receive(:execute_hooks)
@@ -223,7 +223,7 @@ describe Git::BranchPushService, services: true do
end
it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do
- stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+ expect(project.namespace).to receive(:default_branch_protection).and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
diff --git a/spec/services/issues/import_csv_service_spec.rb b/spec/services/issues/import_csv_service_spec.rb
index e7370407d4c..aa43892a36d 100644
--- a/spec/services/issues/import_csv_service_spec.rb
+++ b/spec/services/issues/import_csv_service_spec.rb
@@ -27,6 +27,29 @@ describe Issues::ImportCsvService do
end
end
+ context 'with a file generated by Gitlab CSV export' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_gitlab_export.csv') }
+
+ it 'imports the CSV without errors' do
+ expect_next_instance_of(Notify) do |instance|
+ expect(instance).to receive(:import_issues_csv_email)
+ end
+
+ expect(subject[:success]).to eq(4)
+ expect(subject[:error_lines]).to eq([])
+ expect(subject[:parse_error]).to eq(false)
+ end
+
+ it 'correctly sets the issue attributes' do
+ expect { subject }.to change { project.issues.count }.by 4
+
+ expect(project.issues.reload.last).to have_attributes(
+ title: 'Test Title',
+ description: 'Test Description'
+ )
+ end
+ end
+
context 'comma delimited file' do
let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
@@ -39,6 +62,15 @@ describe Issues::ImportCsvService do
expect(subject[:error_lines]).to eq([])
expect(subject[:parse_error]).to eq(false)
end
+
+ it 'correctly sets the issue attributes' do
+ expect { subject }.to change { project.issues.count }.by 3
+
+ expect(project.issues.reload.last).to have_attributes(
+ title: 'Title with quote"',
+ description: 'Description'
+ )
+ end
end
context 'tab delimited file with error row' do
@@ -53,6 +85,15 @@ describe Issues::ImportCsvService do
expect(subject[:error_lines]).to eq([3])
expect(subject[:parse_error]).to eq(false)
end
+
+ it 'correctly sets the issue attributes' do
+ expect { subject }.to change { project.issues.count }.by 2
+
+ expect(project.issues.reload.last).to have_attributes(
+ title: 'Hello',
+ description: 'World'
+ )
+ end
end
context 'semicolon delimited file with CRLF' do
@@ -67,6 +108,15 @@ describe Issues::ImportCsvService do
expect(subject[:error_lines]).to eq([4])
expect(subject[:parse_error]).to eq(false)
end
+
+ it 'correctly sets the issue attributes' do
+ expect { subject }.to change { project.issues.count }.by 3
+
+ expect(project.issues.reload.last).to have_attributes(
+ title: 'Hello',
+ description: 'World'
+ )
+ end
end
end
end
diff --git a/spec/services/projects/protect_default_branch_service_spec.rb b/spec/services/projects/protect_default_branch_service_spec.rb
index c145b2c06c6..c0b819ab17b 100644
--- a/spec/services/projects/protect_default_branch_service_spec.rb
+++ b/spec/services/projects/protect_default_branch_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe Projects::ProtectDefaultBranchService do
let(:service) { described_class.new(project) }
- let(:project) { instance_spy(Project) }
+ let(:project) { create(:project) }
describe '#execute' do
before do
@@ -147,7 +147,7 @@ describe Projects::ProtectDefaultBranchService do
describe '#protect_branch?' do
context 'when default branch protection is disabled' do
it 'returns false' do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_NONE)
@@ -157,7 +157,7 @@ describe Projects::ProtectDefaultBranchService do
context 'when default branch protection is enabled' do
before do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
@@ -199,7 +199,7 @@ describe Projects::ProtectDefaultBranchService do
describe '#push_access_level' do
context 'when developers can push' do
it 'returns the DEVELOPER access level' do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
@@ -209,7 +209,7 @@ describe Projects::ProtectDefaultBranchService do
context 'when developers can not push' do
it 'returns the MAINTAINER access level' do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
@@ -221,7 +221,7 @@ describe Projects::ProtectDefaultBranchService do
describe '#merge_access_level' do
context 'when developers can merge' do
it 'returns the DEVELOPER access level' do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
@@ -231,7 +231,7 @@ describe Projects::ProtectDefaultBranchService do
context 'when developers can not merge' do
it 'returns the MAINTAINER access level' do
- allow(Gitlab::CurrentSettings)
+ allow(project.namespace)
.to receive(:default_branch_protection)
.and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
diff --git a/spec/support/helpers/wait_for_requests.rb b/spec/support/helpers/wait_for_requests.rb
index d5483d0b0a7..52d1c59ab03 100644
--- a/spec/support/helpers/wait_for_requests.rb
+++ b/spec/support/helpers/wait_for_requests.rb
@@ -34,14 +34,14 @@ module WaitForRequests
# Wait for active Rack requests and client-side AJAX requests
def wait_for_all_requests
wait_for('pending requests complete') do
- finished_all_rack_reqiests? &&
+ finished_all_rack_requests? &&
finished_all_js_requests?
end
end
private
- def finished_all_rack_reqiests?
+ def finished_all_rack_requests?
Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero?
end
diff --git a/yarn.lock b/yarn.lock
index 48e42c00eba..3a98c0e795e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -801,10 +801,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.104.0.tgz#ebbf99788d74b7224f116f1c0040fa0c90034d99"
integrity sha512-lWg/EzxFdbx4YIdDWB2p5ag6Cna78AYGET8nXQYXYwd21/U3wKXKL7vsGR4kOxe1goA9ZAYG9eY+MK7cf+X2cA==
-"@gitlab/ui@^9.18.0":
- version "9.18.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.18.0.tgz#3f4f09e8b7791d0bd01f90920ac6e4477e977ab9"
- integrity sha512-GdQFuH4fPU+/wvX+UL5wSYN6VB2EuIXHBjjrdLHeUhEWuXrtrbBBmtoVEfmii0XcX5iUccgw55orz8Dmq3DlGg==
+"@gitlab/ui@^9.18.2":
+ version "9.18.2"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.18.2.tgz#b82387a8c7bde1db069670596d5ef05d4a16400a"
+ integrity sha512-nBJMIdTX+LYYVGWiF3tdhQ5/tPaYIW80rz8DBzxfLaZYw9pJPolXZ8Vj7xlJWRHbqiM+HghvJPPvgcBXIfKzPw==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"