Commit 35286350 authored by Robert Speicher's avatar Robert Speicher

Merge remote-tracking branch 'dev/master'

parents eb091439 873c4932
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 10.5.3 (2018-03-01)
### Security (2 changes)
- Project can no longer be shared between groups when both member and group locks are active.
- Prevent new push rules from using non-RE2 regexes.
### Fixed (1 change)
- Fix LDAP group sync no longer configurable for regular users.
## 10.5.2 (2018-02-25) ## 10.5.2 (2018-02-25)
- No changes. - No changes.
...@@ -82,6 +94,18 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -82,6 +94,18 @@ Please view this file on the master branch, on stable branches it's out of date.
- Remove unaproved typo check in sast:container report. - Remove unaproved typo check in sast:container report.
## 10.4.5 (2018-03-01)
### Security (2 changes)
- Project can no longer be shared between groups when both member and group locks are active.
- Prevent new push rules from using non-RE2 regexes.
### Fixed (1 change)
- Fix LDAP group sync no longer configurable for regular users.
## 10.4.4 (2018-02-16) ## 10.4.4 (2018-02-16)
### Fixed (4 changes) ### Fixed (4 changes)
...@@ -183,6 +207,18 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -183,6 +207,18 @@ Please view this file on the master branch, on stable branches it's out of date.
- Make scoped issue board specs more reliable. - Make scoped issue board specs more reliable.
## 10.3.8 (2018-03-01)
### Security (2 changes)
- Project can no longer be shared between groups when both member and group locks are active.
- Prevent new push rules from using non-RE2 regexes.
### Fixed (1 change)
- Fix LDAP group sync no longer configurable for regular users.
## 10.3.7 (2018-02-05) ## 10.3.7 (2018-02-05)
### Security (1 change) ### Security (1 change)
......
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.5.3 (2018-03-01)
### Security (1 change)
- Ensure that OTP backup codes are always invalidated.
## 10.5.2 (2018-02-25) ## 10.5.2 (2018-02-25)
### Fixed (7 changes) ### Fixed (7 changes)
...@@ -219,6 +226,13 @@ entry. ...@@ -219,6 +226,13 @@ entry.
- Adds empty state illustration for pending job. - Adds empty state illustration for pending job.
## 10.4.5 (2018-03-01)
### Security (1 change)
- Ensure that OTP backup codes are always invalidated.
## 10.4.4 (2018-02-16) ## 10.4.4 (2018-02-16)
### Security (1 change) ### Security (1 change)
...@@ -443,6 +457,13 @@ entry. ...@@ -443,6 +457,13 @@ entry.
- Use a background migration for issues.closed_at. - Use a background migration for issues.closed_at.
## 10.3.8 (2018-03-01)
### Security (1 change)
- Ensure that OTP backup codes are always invalidated.
## 10.3.7 (2018-02-05) ## 10.3.7 (2018-02-05)
### Security (4 changes) ### Security (4 changes)
......
...@@ -2,6 +2,7 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -2,6 +2,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
layout 'project_settings' layout 'project_settings'
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :authorize_admin_project_member!, only: [:update] before_action :authorize_admin_project_member!, only: [:update]
before_action :authorize_group_share!, only: [:create]
def index def index
redirect_to namespace_project_settings_members_path redirect_to namespace_project_settings_members_path
...@@ -42,6 +43,10 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -42,6 +43,10 @@ class Projects::GroupLinksController < Projects::ApplicationController
protected protected
def authorize_group_share!
access_denied! unless project.allowed_to_share_with_group?
end
def group_link_params def group_link_params
params.require(:group_link).permit(:group_access, :expires_at) params.require(:group_link).permit(:group_access, :expires_at)
end end
......
...@@ -450,6 +450,10 @@ module ProjectsHelper ...@@ -450,6 +450,10 @@ module ProjectsHelper
end end
end end
def project_can_be_shared?
!membership_locked? || @project.allowed_to_share_with_group?
end
def membership_locked? def membership_locked?
if @project.group && @project.group.membership_lock if @project.group && @project.group.membership_lock
true true
...@@ -458,6 +462,24 @@ module ProjectsHelper ...@@ -458,6 +462,24 @@ module ProjectsHelper
end end
end end
def share_project_description
share_with_group = @project.allowed_to_share_with_group?
share_with_members = !membership_locked?
project_name = content_tag(:strong, @project.name)
member_message = "You can add a new member to #{project_name}"
description =
if share_with_group && share_with_members
"#{member_message} or share it with another group."
elsif share_with_group
"You can share #{project_name} with another group."
elsif share_with_members
"#{member_message}."
end
description.to_s.html_safe
end
def readme_cache_key def readme_cache_key
sha = @project.commit.try(:sha) || 'nil' sha = @project.commit.try(:sha) || 'nil'
[@project.full_path, sha, "readme"].join('-') [@project.full_path, sha, "readme"].join('-')
......
class UntrustedRegexpValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return unless value
Gitlab::UntrustedRegexp.new(value)
rescue RegexpError => e
record.errors.add(attribute, "not valid RE2 syntax: #{e.message}")
end
end
- page_title "Members" - page_title "Members"
- can_admin_project_members = can?(current_user, :admin_project_member, @project)
.row.prepend-top-default .row.prepend-top-default
.col-lg-12 .col-lg-12
%h4 - if project_can_be_shared?
Project members %h4
- if can?(current_user, :admin_project_member, @project) Project members
%p - if can_admin_project_members
You can add a new member to %p= share_project_description
%strong= @project.name - else
or share it with another group. %p
- else Members can be added by project
%p %i Masters
Members can be added by project or
%i Masters %i Owners
or
%i Owners
.light .light
- if can?(current_user, :admin_project_member, @project) - if can_admin_project_members && project_can_be_shared?
%ul.nav-links.gitlab-tabs{ role: 'tablist' } - if !membership_locked? && @project.allowed_to_share_with_group?
- if !membership_locked? %ul.nav-links.gitlab-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' } %li.active{ role: 'presentation' }
%a{ href: '#add-member-pane', id: 'add-member-tab', data: { toggle: 'tab' }, role: 'tab' } Add member %a{ href: '#add-member-pane', id: 'add-member-tab', data: { toggle: 'tab' }, role: 'tab' } Add member
- if @project.allowed_to_share_with_group?
%li{ role: 'presentation', class: ('active' if membership_locked?) } %li{ role: 'presentation', class: ('active' if membership_locked?) }
%a{ href: '#share-with-group-pane', id: 'share-with-group-tab', data: { toggle: 'tab' }, role: 'tab' } Share with group %a{ href: '#share-with-group-pane', id: 'share-with-group-tab', data: { toggle: 'tab' }, role: 'tab' } Share with group
.tab-content.gitlab-tab-content .tab-content.gitlab-tab-content
- if !membership_locked?
.tab-pane.active{ id: 'add-member-pane', role: 'tabpanel' } .tab-pane.active{ id: 'add-member-pane', role: 'tabpanel' }
= render 'projects/project_members/new_project_member', tab_title: 'Add member' = render 'projects/project_members/new_project_member', tab_title: 'Add member'
.tab-pane{ id: 'share-with-group-pane', role: 'tabpanel', class: ('active' if membership_locked?) } .tab-pane{ id: 'share-with-group-pane', role: 'tabpanel', class: ('active' if membership_locked?) }
= render 'projects/project_members/new_shared_group', tab_title: 'Share with group' = render 'projects/project_members/new_shared_group', tab_title: 'Share with group'
- elsif !membership_locked?
.add-member= render 'projects/project_members/new_project_member', tab_title: 'Add member'
- elsif @project.allowed_to_share_with_group?
.share-with-group= render 'projects/project_members/new_shared_group', tab_title: 'Share with group'
= render 'shared/members/requests', membership_source: @project, requesters: @requesters = render 'shared/members/requests', membership_source: @project, requesters: @requesters
.clearfix .clearfix
......
---
title: Project can no longer be shared between groups when both member and group locks
are active
merge_request:
author:
type: security
---
title: Prevent new push rules from using non-RE2 regexes
merge_request:
author:
type: security
---
title: Fix LDAP group sync no longer configurable for regular users
merge_request:
author:
type: fixed
class AddRegexpUsesRe2ToPushRules < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
# Default value to true for new values while keeping NULL for existing ones
add_column :push_rules, :regexp_uses_re2, :boolean
change_column_default :push_rules, :regexp_uses_re2, true
end
def down
remove_column :push_rules, :regexp_uses_re2
end
end
...@@ -2060,6 +2060,7 @@ ActiveRecord::Schema.define(version: 20180306074045) do ...@@ -2060,6 +2060,7 @@ ActiveRecord::Schema.define(version: 20180306074045) do
t.string "branch_name_regex" t.string "branch_name_regex"
t.boolean "reject_unsigned_commits" t.boolean "reject_unsigned_commits"
t.boolean "commit_committer_check" t.boolean "commit_committer_check"
t.boolean "regexp_uses_re2", default: true
end end
add_index "push_rules", ["is_sample"], name: "index_push_rules_on_is_sample", where: "is_sample", using: :btree add_index "push_rules", ["is_sample"], name: "index_push_rules_on_is_sample", where: "is_sample", using: :btree
......
...@@ -340,7 +340,6 @@ data before running `pg_basebackup`. ...@@ -340,7 +340,6 @@ data before running `pg_basebackup`.
echo Cleaning up old cluster directory echo Cleaning up old cluster directory
sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data
rm -f /tmp/postgresql.trigger
echo Starting base backup as the replicator user echo Starting base backup as the replicator user
echo Enter the password for $USER@$HOST echo Enter the password for $USER@$HOST
...@@ -350,7 +349,6 @@ data before running `pg_basebackup`. ...@@ -350,7 +349,6 @@ data before running `pg_basebackup`.
sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_ sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_
standby_mode = 'on' standby_mode = 'on'
primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE' primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE'
trigger_file = '/tmp/postgresql.trigger'
_EOF1_ _EOF1_
" "
......
...@@ -66,14 +66,14 @@ The following options are available. ...@@ -66,14 +66,14 @@ The following options are available.
| Check whether committer is the current authenticated user | **Premium** 10.2 | GitLab will reject any commit that was not committed by the current authenticated user | | Check whether committer is the current authenticated user | **Premium** 10.2 | GitLab will reject any commit that was not committed by the current authenticated user |
| Check whether commit is signed through GPG | **Premium** 10.1 | Reject commit when it is not signed through GPG. Read [signing commits with GPG][signing-commits]. | | Check whether commit is signed through GPG | **Premium** 10.1 | Reject commit when it is not signed through GPG. Read [signing commits with GPG][signing-commits]. |
| Prevent committing secrets to Git | **Starter** 8.12 | GitLab will reject any files that are likely to contain secrets. Read [what files are forbidden](#prevent-pushing-secrets-to-the-repository). | | Prevent committing secrets to Git | **Starter** 8.12 | GitLab will reject any files that are likely to contain secrets. Read [what files are forbidden](#prevent-pushing-secrets-to-the-repository). |
| Restrict by commit message | **Starter** 7.10 | Only commit messages that match this Ruby regular expression are allowed to be pushed. Leave empty to allow any commit message. | | Restrict by commit message | **Starter** 7.10 | Only commit messages that match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by branch name | **Starter** 9.3 | Only branch names that match this Ruby regular expression are allowed to be pushed. Leave empty to allow any branch name. | | Restrict by branch name | **Starter** 9.3 | Only branch names that match this regular expression are allowed to be pushed. Leave empty to allow any branch name. |
| Restrict by commit author's email | **Starter** 7.10 | Only commit author's email that match this Ruby regular expression are allowed to be pushed. Leave empty to allow any email. | | Restrict by commit author's email | **Starter** 7.10 | Only commit author's email that match this regular expression are allowed to be pushed. Leave empty to allow any email. |
| Prohibited file names | **Starter** 7.10 | Any committed filenames that match this Ruby regular expression are not allowed to be pushed. Leave empty to allow any filenames. | | Prohibited file names | **Starter** 7.10 | Any committed filenames that match this regular expression are not allowed to be pushed. Leave empty to allow any filenames. |
| Maximum file size | **Starter** 7.12 | Pushes that contain added or updated files that exceed this file size (in MB) are rejected. Set to 0 to allow files of any size. | | Maximum file size | **Starter** 7.12 | Pushes that contain added or updated files that exceed this file size (in MB) are rejected. Set to 0 to allow files of any size. |
>**Tip:** >**Tip:**
You can check your regular expressions at <http://rubular.com>. GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in push rules. You can check your regular expressions at <https://regex-golang.appspot.com>.
## Prevent pushing secrets to the repository ## Prevent pushing secrets to the repository
......
class PushRule < ActiveRecord::Base class PushRule < ActiveRecord::Base
MatchError = Class.new(StandardError) MatchError = Class.new(StandardError)
REGEX_COLUMNS = %i[
force_push_regex
delete_branch_regex
commit_message_regex
author_email_regex
file_name_regex
branch_name_regex
].freeze
belongs_to :project belongs_to :project
validates :project, presence: true, unless: "is_sample?" validates :project, presence: true, unless: "is_sample?"
validates :max_file_size, numericality: { greater_than_or_equal_to: 0, only_integer: true } validates :max_file_size, numericality: { greater_than_or_equal_to: 0, only_integer: true }
validates(*REGEX_COLUMNS, untrusted_regexp: true)
before_update :convert_to_re2
FILES_BLACKLIST = YAML.load_file(Rails.root.join('ee/lib/gitlab/checks/files_blacklist.yml')) FILES_BLACKLIST = YAML.load_file(Rails.root.join('ee/lib/gitlab/checks/files_blacklist.yml'))
SETTINGS_WITH_GLOBAL_DEFAULT = %i[ SETTINGS_WITH_GLOBAL_DEFAULT = %i[
...@@ -43,7 +55,7 @@ class PushRule < ActiveRecord::Base ...@@ -43,7 +55,7 @@ class PushRule < ActiveRecord::Base
end end
def commit_message_allowed?(message) def commit_message_allowed?(message)
data_match?(message, commit_message_regex) data_match?(message, commit_message_regex, multiline: true)
end end
def branch_name_allowed?(branch) def branch_name_allowed?(branch)
...@@ -94,9 +106,15 @@ class PushRule < ActiveRecord::Base ...@@ -94,9 +106,15 @@ class PushRule < ActiveRecord::Base
private private
def data_match?(data, regex) def data_match?(data, regex, multiline: false)
if regex.present? if regex.present?
!!(data =~ Regexp.new(regex)) regexp = if allow_regex_fallback?
Gitlab::UntrustedRegexp.with_fallback(regex, multiline: multiline)
else
Gitlab::UntrustedRegexp.new(regex, multiline: multiline)
end
regexp === data
else else
true true
end end
...@@ -104,6 +122,16 @@ class PushRule < ActiveRecord::Base ...@@ -104,6 +122,16 @@ class PushRule < ActiveRecord::Base
raise MatchError, "Regular expression '#{regex}' is invalid: #{e.message}" raise MatchError, "Regular expression '#{regex}' is invalid: #{e.message}"
end end
def convert_to_re2
self.regexp_uses_re2 = true
end
# Allow fallback to ruby regex library
# Only supported for existing regexes due to denial of service risk
def allow_regex_fallback?
!regexp_uses_re2?
end
def read_setting_with_global_default(setting) def read_setting_with_global_default(setting)
value = read_attribute(setting) value = read_attribute(setting)
......
module API module API
class Ldap < Grape::API class Ldap < Grape::API
before { authenticated_as_admin! } # Admin users by default should be able to access these API endpoints.
# However, non-admin users can access these endpoints if the "Allow group
# owners to manage LDAP-related group settings" is enabled, and they own a
# group.
before { authenticated_with_ldap_admin_access! }
resource :ldap do resource :ldap do
helpers do helpers do
......
...@@ -26,6 +26,21 @@ module EE ...@@ -26,6 +26,21 @@ module EE
render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409) render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409)
end end
end end
# Normally, only admin users should have access to see LDAP
# groups. However, due to the "Allow group owners to manage LDAP-related
# group settings" setting, any group owner can sync LDAP groups with
# their project.
#
# In the future, we should also check that the user has access to manage
# a specific group so that we can use the Ability class.
def authenticated_with_ldap_admin_access!
authenticate!
forbidden! unless current_user.admin? ||
::Gitlab::CurrentSettings.current_application_settings
.allow_group_owners_to_manage_ldap
end
end end
end end
end end
...@@ -13,6 +13,71 @@ describe PushRule do ...@@ -13,6 +13,71 @@ describe PushRule do
describe "Validation" do describe "Validation" do
it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_numericality_of(:max_file_size).is_greater_than_or_equal_to(0).only_integer } it { is_expected.to validate_numericality_of(:max_file_size).is_greater_than_or_equal_to(0).only_integer }
it 'validates RE2 regex syntax' do
push_rule = build(:push_rule, branch_name_regex: '(ee|ce).*\1')
expect(push_rule).not_to be_valid
expect(push_rule.errors.full_messages.join).to match /invalid escape sequence/
end
end
it 'defaults regexp_uses_re2 to true' do
push_rule = create(:push_rule)
expect(push_rule.regexp_uses_re2).to eq(true)
end
it 'updates regexp_uses_re2 to true on edit' do
push_rule = create(:push_rule, regexp_uses_re2: nil)
expect do
push_rule.update!(branch_name_regex: '.*')
end.to change(push_rule, :regexp_uses_re2).to true
end
describe '#branch_name_allowed?' do
subject(:push_rule) { create(:push_rule, branch_name_regex: '\d+\-.*')}
it 'checks branch against regex' do
expect(subject.branch_name_allowed?('123-feature')).to be true
expect(subject.branch_name_allowed?('feature-123')).to be false
end
it 'uses RE2 regex engine' do
expect_any_instance_of(Gitlab::UntrustedRegexp).to receive(:===)
subject.branch_name_allowed?('123-feature')
end
context 'with legacy regex' do
before do
push_rule.update_column(:regexp_uses_re2, nil)
end
it 'attempts to use safe RE2 regex engine' do
expect_any_instance_of(Gitlab::UntrustedRegexp).to receive(:===)
subject.branch_name_allowed?('ee-feature-ee')
end
it 'falls back to ruby regex engine' do
push_rule.update_column(:branch_name_regex, '(ee|ce).*\1')
expect(subject.branch_name_allowed?('ee-feature-ee')).to be true
expect(subject.branch_name_allowed?('ee-feature-ce')).to be false
end
end
end
describe '#commit_message_allowed?' do
subject(:push_rule) { create(:push_rule, commit_message_regex: '^Signed-off-by')}
it 'uses multiline regex' do
commit_message = "Some git commit feature\n\nSigned-off-by: Someone"
expect(subject.commit_message_allowed?(commit_message)).to be true
end
end end
describe '#commit_validation?' do describe '#commit_validation?' do
......
...@@ -17,6 +17,7 @@ describe API::Ldap do ...@@ -17,6 +17,7 @@ describe API::Ldap do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true)
allow(Gitlab::Auth::LDAP::Adapter).to receive(:new).and_return(adapter) allow(Gitlab::Auth::LDAP::Adapter).to receive(:new).and_return(adapter)
allow(adapter).to receive_messages(groups: groups) allow(adapter).to receive_messages(groups: groups)
stub_application_setting(allow_group_owners_to_manage_ldap: false)
end end
describe "GET /ldap/groups" do describe "GET /ldap/groups" do
...@@ -34,6 +35,20 @@ describe API::Ldap do ...@@ -34,6 +35,20 @@ describe API::Ldap do
end end
end end
context 'when group owners are allowed to manage LDAP' do
before do
stub_application_setting(allow_group_owners_to_manage_ldap: true)
end
it "returns an array of ldap groups" do
get api("/ldap/groups", user)
expect(response.status).to eq 200
expect(json_response).to be_an Array
expect(json_response.length).to eq 2
expect(json_response.first['cn']).to eq 'developers'
end
end
context "when authenticated as admin" do context "when authenticated as admin" do
it "returns an array of ldap groups" do it "returns an array of ldap groups" do
get api("/ldap/groups", admin) get api("/ldap/groups", admin)
...@@ -60,6 +75,20 @@ describe API::Ldap do ...@@ -60,6 +75,20 @@ describe API::Ldap do
end end
end end
context 'when group owners are allowed to manage LDAP' do
before do
stub_application_setting(allow_group_owners_to_manage_ldap: true)
end
it "returns an array of ldap groups" do
get api("/ldap/ldapmain/groups", admin)
expect(response.status).to eq 200
expect(json_response).to be_an Array
expect(json_response.length).to eq 2
expect(json_response.first['cn']).to eq 'developers'
end
end
context "when authenticated as admin" do context "when authenticated as admin" do
it "returns an array of ldap groups" do it "returns an array of ldap groups" do
get api("/ldap/ldapmain/groups", admin) get api("/ldap/ldapmain/groups", admin)
......
...@@ -11,7 +11,11 @@ module Gitlab ...@@ -11,7 +11,11 @@ module Gitlab
class UntrustedRegexp class UntrustedRegexp
delegate :===, to: :regexp delegate :===, to: :regexp
def initialize(pattern) def initialize(pattern, multiline: false)
if multiline
pattern = "(?m)#{pattern}"
end
@regexp = RE2::Regexp.new(pattern, log_errors: false) @regexp = RE2::Regexp.new(pattern, log_errors: false)
raise RegexpError.new(regexp.error) unless regexp.ok? raise RegexpError.new(regexp.error) unless regexp.ok?
...@@ -31,6 +35,19 @@ module Gitlab ...@@ -31,6 +35,19 @@ module Gitlab
RE2.Replace(text, regexp, rewrite) RE2.Replace(text, regexp, rewrite)
end end
# Handles regular expressions with the preferred RE2 library where possible
# via UntustedRegex. Falls back to Ruby's built-in regular expression library
# when the syntax would be invalid in RE2.
#
# One difference between these is `(?m)` multi-line mode. Ruby regex enables
# this by default, but also handles `^` and `$` differently.
# See: https://www.regular-expressions.info/modifiers.html
def self.with_fallback(pattern, multiline: false)
UntrustedRegexp.new(pattern, multiline: multiline)
rescue RegexpError
Regexp.new(pattern)
end
private private
attr_reader :regexp attr_reader :regexp
......
...@@ -21,6 +21,18 @@ describe Projects::GroupLinksController do ...@@ -21,6 +21,18 @@ describe Projects::GroupLinksController do
end end
end end
context 'when project is not allowed to be shared with a group' do
before do
group.update_attributes(share_with_group_lock: false)
end
include_context 'link project to group'
it 'responds with status 404' do
expect(response).to have_gitlab_http_status(404)
end
end
context 'when user has access to group he want to link project to' do context 'when user has access to group he want to link project to' do
before do before do
group.add_developer(user) group.add_developer(user)
......
...@@ -7,18 +7,47 @@ feature 'Project > Members > Share with Group', :js do ...@@ -7,18 +7,47 @@ feature 'Project > Members > Share with Group', :js do
let(:master) { create(:user) } let(:master) { create(:user) }
describe 'Share with group lock' do describe 'Share with group lock' do
shared_examples 'the project can be shared with groups' do shared_examples 'the project cannot be shared with groups' do
scenario 'the "Share with group" tab exists' do scenario 'user is only able to share with members' do
visit project_settings_members_path(project) visit project_settings_members_path(project)
expect(page).to have_selector('#share-with-group-tab')
expect(page).not_to have_selector('#add-member-tab')
expect(page).not_to have_selector('#share-with-group-tab')
expect(page).not_to have_selector('.share-with-group')
expect(page).to have_selector('.add-member')
end end
end end
shared_examples 'the project cannot be shared with groups' do shared_examples 'the project cannot be shared with members' do
scenario 'the "Share with group" tab does not exist' do scenario 'user is only able to share with groups' do
visit project_settings_members_path(project) visit project_settings_members_path(project)
expect(page).to have_selector('#add-member-tab')
expect(page).not_to have_selector('#add-member-tab')
expect(page).not_to have_selector('#share-with-group-tab') expect(page).not_to have_selector('#share-with-group-tab')
expect(page).not_to have_selector('.add-member')
expect(page).to have_selector('.share-with-group')
end
end
shared_examples 'the project cannot be shared with groups and members' do
scenario 'no tabs or share content exists' do
visit project_settings_members_path(project)
expect(page).not_to have_selector('#add-member-tab')
expect(page).not_to have_selector('#share-with-group-tab')
expect(page).not_to have_selector('.add-member')
expect(page).not_to have_selector('.share-with-group')
end
end
shared_examples 'the project can be shared with groups and members' do
scenario 'both member and group tabs exist' do
visit project_settings_members_path(project)
expect(page).not_to have_selector('.add-member')
expect(page).not_to have_selector('.share-with-group')
expect(page).to have_selector('#add-member-tab')
expect(page).to have_selector('#share-with-group-tab')
end end
end end
...@@ -31,8 +60,8 @@ feature 'Project > Members > Share with Group', :js do ...@@ -31,8 +60,8 @@ feature 'Project > Members > Share with Group', :js do
sign_in(master) sign_in(master)
end end
context 'when the group has "Share with group lock" disabled' do context 'when the group has "Share with group lock" and "Member lock" disabled' do
it_behaves_like 'the project can be shared with groups' it_behaves_like 'the project can be shared with groups and members'
scenario 'the project can be shared with another group' do scenario 'the project can be shared with another group' do
visit project_settings_members_path(project) visit project_settings_members_path(project)
...@@ -56,10 +85,25 @@ feature 'Project > Members > Share with Group', :js do ...@@ -56,10 +85,25 @@ feature 'Project > Members > Share with Group', :js do
it_behaves_like 'the project cannot be shared with groups' it_behaves_like 'the project cannot be shared with groups'
end end
context 'when the group has membership lock enabled' do
before do
project.namespace.update_column(:membership_lock, true)
end
it_behaves_like 'the project cannot be shared with members'
end
context 'when the group has membership lock and "Share with group lock" enabled' do
before do
project.namespace.update_attributes(share_with_group_lock: true, membership_lock: true)
end
it_behaves_like 'the project cannot be shared with groups and members'
end
end end
context 'for a project in a subgroup', :nested_groups do context 'for a project in a subgroup', :nested_groups do
let!(:group_to_share_with) { create(:group) }
let(:root_group) { create(:group) } let(:root_group) { create(:group) }
let(:subgroup) { create(:group, parent: root_group) } let(:subgroup) { create(:group, parent: root_group) }
let(:project) { create(:project, namespace: subgroup) } let(:project) { create(:project, namespace: subgroup) }
...@@ -69,9 +113,9 @@ feature 'Project > Members > Share with Group', :js do ...@@ -69,9 +113,9 @@ feature 'Project > Members > Share with Group', :js do
sign_in(master) sign_in(master)
end end
context 'when the root_group has "Share with group lock" disabled' do context 'when the root_group has "Share with group lock" and membership lock disabled' do
context 'when the subgroup has "Share with group lock" disabled' do context 'when the subgroup has "Share with group lock" and membership lock disabled' do
it_behaves_like 'the project can be shared with groups' it_behaves_like 'the project can be shared with groups and members'
end end
context 'when the subgroup has "Share with group lock" enabled' do context 'when the subgroup has "Share with group lock" enabled' do
...@@ -81,24 +125,67 @@ feature 'Project > Members > Share with Group', :js do ...@@ -81,24 +125,67 @@ feature 'Project > Members > Share with Group', :js do
it_behaves_like 'the project cannot be shared with groups' it_behaves_like 'the project cannot be shared with groups'
end end
context 'when the subgroup has membership lock enabled' do
before do
subgroup.update_column(:membership_lock, true)
end
it_behaves_like 'the project cannot be shared with members'
end
context 'when the group has membership lock and "Share with group lock" enabled' do
before do
subgroup.update_attributes(share_with_group_lock: true, membership_lock: true)
end
it_behaves_like 'the project cannot be shared with groups and members'
end
end end
context 'when the root_group has "Share with group lock" enabled' do context 'when the root_group has "Share with group lock" and membership lock enabled' do
before do before do
root_group.update_column(:share_with_group_lock, true) root_group.update_attributes(share_with_group_lock: true, membership_lock: true)
subgroup.reload
end
# This behaviour should be changed to disable sharing with members as well
# See: https://gitlab.com/gitlab-org/gitlab-ce/issues/42093
it_behaves_like 'the project cannot be shared with groups'
context 'when the subgroup has "Share with group lock" and membership lock disabled (parent overridden)' do
before do
subgroup.update_attributes(share_with_group_lock: false, membership_lock: false)
end
it_behaves_like 'the project can be shared with groups and members'
end end
context 'when the subgroup has "Share with group lock" disabled (parent overridden)' do # This behaviour should be changed to disable sharing with members as well
it_behaves_like 'the project can be shared with groups' # See: https://gitlab.com/gitlab-org/gitlab-ce/issues/42093
context 'when the subgroup has membership lock enabled (parent overridden)' do
before do
subgroup.update_column(:membership_lock, true)
end
it_behaves_like 'the project cannot be shared with groups and members'
end end
context 'when the subgroup has "Share with group lock" enabled' do context 'when the subgroup has "Share with group lock" enabled (parent overridden)' do
before do before do
subgroup.update_column(:share_with_group_lock, true) subgroup.update_column(:share_with_group_lock, true)
end end
it_behaves_like 'the project cannot be shared with groups' it_behaves_like 'the project cannot be shared with groups'
end end
context 'when the subgroup has "Share with group lock" and membership lock enabled' do
before do
subgroup.update_attributes(membership_lock: true, share_with_group_lock: true)
end
it_behaves_like 'the project cannot be shared with groups and members'
end
end end
end end
end end
......
...@@ -39,6 +39,14 @@ describe Gitlab::UntrustedRegexp do ...@@ -39,6 +39,14 @@ describe Gitlab::UntrustedRegexp do
expect(result).to be_falsy expect(result).to be_falsy
end end
it 'can handle regular expressions in multiline mode' do
regexp = described_class.new('^\d', multiline: true)
result = regexp === "Header\n\n1. Content"
expect(result).to be_truthy
end
end end
describe '#scan' do describe '#scan' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment