Skip to content
Snippets Groups Projects
Commit 52b9f101 authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot
Browse files

Merge remote-tracking branch 'dev/12-5-stable' into 12-5-stable

parents 4c442bdd ef6512ad
No related branches found
No related tags found
No related merge requests found
Showing
with 710 additions and 52 deletions
Loading
Loading
@@ -285,6 +285,70 @@ describe Note do
end
end
 
describe "#visible_for?" do
using RSpec::Parameterized::TableSyntax
let_it_be(:note) { create(:note) }
let_it_be(:user) { create(:user) }
where(:cross_reference_visible, :system_note_viewable, :result) do
true | true | false
false | true | true
false | false | false
end
with_them do
it "returns expected result" do
expect(note).to receive(:cross_reference_not_visible_for?).and_return(cross_reference_visible)
unless cross_reference_visible
expect(note).to receive(:system_note_viewable_by?)
.with(user).and_return(system_note_viewable)
end
expect(note.visible_for?(user)).to eq result
end
end
end
describe "#system_note_viewable_by?(user)" do
let_it_be(:note) { create(:note) }
let_it_be(:user) { create(:user) }
let!(:metadata) { create(:system_note_metadata, note: note, action: "branch") }
context "when system_note_metadata is not present" do
it "returns true" do
expect(note).to receive(:system_note_metadata).and_return(nil)
expect(note.send(:system_note_viewable_by?, user)).to be_truthy
end
end
context "system_note_metadata isn't of type 'branch'" do
before do
metadata.action = "not_a_branch"
end
it "returns true" do
expect(note.send(:system_note_viewable_by?, user)).to be_truthy
end
end
context "user doesn't have :download_code ability" do
it "returns false" do
expect(note.send(:system_note_viewable_by?, user)).to be_falsey
end
end
context "user has the :download_code ability" do
it "returns true" do
expect(Ability).to receive(:allowed?).with(user, :download_code, note.project).and_return(true)
expect(note.send(:system_note_viewable_by?, user)).to be_truthy
end
end
end
describe "cross_reference_not_visible_for?" do
let(:private_user) { create(:user) }
let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_maintainer(private_user) } }
Loading
Loading
Loading
Loading
@@ -6,6 +6,16 @@ describe ProjectFeature do
let(:project) { create(:project) }
let(:user) { create(:user) }
 
describe 'PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT' do
it 'has higher level than that of PRIVATE_FEATURES_MIN_ACCESS_LEVEL' do
described_class::PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT.each do |feature, level|
if generic_level = described_class::PRIVATE_FEATURES_MIN_ACCESS_LEVEL[feature]
expect(level).to be >= generic_level
end
end
end
end
describe '.quoted_access_level_column' do
it 'returns the table name and quoted column name for a feature' do
expected = '"project_features"."issues_access_level"'
Loading
Loading
@@ -246,10 +256,24 @@ describe ProjectFeature do
expect(described_class.required_minimum_access_level('merge_requests')).to eq(Gitlab::Access::REPORTER)
end
 
it 'handles repository' do
expect(described_class.required_minimum_access_level(:repository)).to eq(Gitlab::Access::GUEST)
end
it 'raises error if feature is invalid' do
expect do
described_class.required_minimum_access_level(:foos)
end.to raise_error
end
end
describe '.required_minimum_access_level_for_private_project' do
it 'returns higher permission for repository' do
expect(described_class.required_minimum_access_level_for_private_project(:repository)).to eq(Gitlab::Access::REPORTER)
end
it 'returns normal permission for issues' do
expect(described_class.required_minimum_access_level_for_private_project(:issues)).to eq(Gitlab::Access::GUEST)
end
end
end
Loading
Loading
@@ -30,7 +30,8 @@ describe ChatNotificationService do
end
 
describe '#execute' do
let(:chat_service) { described_class.new }
subject(:chat_service) { described_class.new }
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:webhook_url) { 'https://example.gitlab.com/' }
Loading
Loading
@@ -53,12 +54,7 @@ describe ChatNotificationService do
subject.project = project
data = Gitlab::DataBuilder::Push.build_sample(project, user)
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, {})
.and_return(
double(:slack_service).as_null_object
)
expect(chat_service).to receive(:notify).and_return(true)
expect(chat_service.execute(data)).to be true
end
end
Loading
Loading
@@ -68,12 +64,7 @@ describe ChatNotificationService do
subject.project = create(:project, :empty_repo)
data = Gitlab::DataBuilder::Push.build_sample(subject.project, user)
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, {})
.and_return(
double(:slack_service).as_null_object
)
expect(chat_service).to receive(:notify).and_return(true)
expect(chat_service.execute(data)).to be true
end
end
Loading
Loading
Loading
Loading
@@ -3,5 +3,5 @@
require 'spec_helper'
 
describe SlackService do
it_behaves_like "slack or mattermost notifications", "Slack"
it_behaves_like "slack or mattermost notifications", 'Slack'
end
Loading
Loading
@@ -2924,7 +2924,7 @@ describe Project do
end
 
describe '#any_lfs_file_locks?', :request_store do
set(:project) { create(:project) }
let_it_be(:project) { create(:project) }
 
it 'returns false when there are no LFS file locks' do
expect(project.any_lfs_file_locks?).to be_falsey
Loading
Loading
@@ -3411,6 +3411,20 @@ describe Project do
expect(projects).to eq([public_project])
end
end
context 'min_access_level' do
let!(:private_project) { create(:project, :private) }
before do
private_project.add_guest(user)
end
it 'excludes projects when user does not have required minimum access level' do
projects = described_class.all.public_or_visible_to_user(user, Gitlab::Access::REPORTER)
expect(projects).to contain_exactly(public_project)
end
end
end
 
describe '.ids_with_issuables_available_for' do
Loading
Loading
@@ -3539,7 +3553,7 @@ describe Project do
include ProjectHelpers
using RSpec::Parameterized::TableSyntax
 
set(:group) { create(:group) }
let_it_be(:group) { create(:group) }
let!(:project) { create(:project, project_level, namespace: group ) }
let(:user) { create_user_from_membership(project, membership) }
 
Loading
Loading
@@ -3562,6 +3576,66 @@ describe Project do
end
end
end
context 'issues' do
let(:feature) { Issue }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
context 'wiki' do
let(:feature) { :wiki }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
context 'code' do
let(:feature) { :repository }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access_and_non_private_project_only
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
expected_objects = expected_count == 1 ? [project] : []
expect(
described_class.filter_by_feature_visibility(feature, user)
).to eq(expected_objects)
end
end
end
end
 
describe '#pages_available?' do
Loading
Loading
Loading
Loading
@@ -49,6 +49,8 @@ shared_examples 'languages and percentages JSON response' do
end
 
describe API::Projects do
include ProjectForksHelper
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
Loading
Loading
@@ -1163,6 +1165,18 @@ describe API::Projects do
expect(json_response.keys).not_to include('permissions')
end
 
context 'the project is a public fork' do
it 'hides details of a public fork parent' do
public_project = create(:project, :repository, :public)
fork = fork_project(public_project)
get api("/projects/#{fork.id}")
expect(response).to have_gitlab_http_status(200)
expect(json_response['forked_from_project']).to be_nil
end
end
context 'and the project has a private repository' do
let(:project) { create(:project, :repository, :public, :repository_private) }
let(:protected_attributes) { %w(default_branch ci_config_path) }
Loading
Loading
@@ -1479,6 +1493,28 @@ describe API::Projects do
end
end
 
context 'the project is a fork' do
it 'shows details of a visible fork parent' do
fork = fork_project(project, user)
get api("/projects/#{fork.id}", user)
expect(response).to have_gitlab_http_status(200)
expect(json_response['forked_from_project']).to include('id' => project.id)
end
it 'hides details of a hidden fork parent' do
fork = fork_project(project, user)
fork_user = create(:user)
fork.team.add_developer(fork_user)
get api("/projects/#{fork.id}", fork_user)
expect(response).to have_gitlab_http_status(200)
expect(json_response['forked_from_project']).to be_nil
end
end
describe 'permissions' do
context 'all projects' do
before do
Loading
Loading
Loading
Loading
@@ -10,16 +10,18 @@ module ProjectHelpers
nil
when :non_member
create(:user, name: membership)
when :admin
create(:user, :admin, name: 'admin')
else
create(:user, name: membership).tap { |u| target.add_user(u, membership) }
end
end
 
def update_feature_access_level(project, access_level)
project.update!(
repository_access_level: access_level,
merge_requests_access_level: access_level,
builds_access_level: access_level
)
features = ProjectFeature::FEATURES.dup
features.delete(:pages)
params = features.each_with_object({}) { |feature, h| h["#{feature}_access_level"] = access_level }
project.update!(params)
end
end
Loading
Loading
@@ -20,6 +20,12 @@ module SearchHelpers
end
end
 
def has_search_scope?(scope)
page.within '.search-filter' do
has_link?(scope)
end
end
def max_limited_count
Gitlab::SearchResults::COUNT_LIMIT_MESSAGE
end
Loading
Loading
Loading
Loading
@@ -3,13 +3,28 @@
RSpec.shared_context 'ProjectPolicyTable context' do
using RSpec::Parameterized::TableSyntax
 
let(:pendings) { {} }
let(:pending?) do
pendings.include?(
{
project_level: project_level,
feature_access_level: feature_access_level,
membership: membership,
expected_count: expected_count
}
)
end
# rubocop:disable Metrics/AbcSize
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_reporter_feature_access
:public | :enabled | :admin | 1
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
:public | :enabled | :non_member | 1
:public | :enabled | :anonymous | 1
 
:public | :private | :admin | 1
:public | :private | :reporter | 1
:public | :private | :guest | 0
:public | :private | :non_member | 0
Loading
Loading
@@ -20,11 +35,13 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:public | :disabled | :non_member | 0
:public | :disabled | :anonymous | 0
 
:internal | :enabled | :admin | 1
:internal | :enabled | :reporter | 1
:internal | :enabled | :guest | 1
:internal | :enabled | :non_member | 1
:internal | :enabled | :anonymous | 0
 
:internal | :private | :admin | 1
:internal | :private | :reporter | 1
:internal | :private | :guest | 0
:internal | :private | :non_member | 0
Loading
Loading
@@ -35,11 +52,7 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
 
:private | :enabled | :reporter | 1
:private | :enabled | :guest | 1
:private | :enabled | :non_member | 0
:private | :enabled | :anonymous | 0
:private | :private | :admin | 1
:private | :private | :reporter | 1
:private | :private | :guest | 0
:private | :private | :non_member | 0
Loading
Loading
@@ -51,12 +64,15 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:private | :disabled | :anonymous | 0
end
 
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_guest_feature_access
:public | :enabled | :admin | 1
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
:public | :enabled | :non_member | 1
:public | :enabled | :anonymous | 1
 
:public | :private | :admin | 1
:public | :private | :reporter | 1
:public | :private | :guest | 1
:public | :private | :non_member | 0
Loading
Loading
@@ -67,11 +83,13 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:public | :disabled | :non_member | 0
:public | :disabled | :anonymous | 0
 
:internal | :enabled | :admin | 1
:internal | :enabled | :reporter | 1
:internal | :enabled | :guest | 1
:internal | :enabled | :non_member | 1
:internal | :enabled | :anonymous | 0
 
:internal | :private | :admin | 1
:internal | :private | :reporter | 1
:internal | :private | :guest | 1
:internal | :private | :non_member | 0
Loading
Loading
@@ -82,11 +100,7 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
 
:private | :enabled | :reporter | 1
:private | :enabled | :guest | 1
:private | :enabled | :non_member | 0
:private | :enabled | :anonymous | 0
:private | :private | :admin | 1
:private | :private | :reporter | 1
:private | :private | :guest | 1
:private | :private | :non_member | 0
Loading
Loading
@@ -98,6 +112,196 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:private | :disabled | :anonymous | 0
end
 
# This table is based on permission_table_for_guest_feature_access,
# but with a slight twist.
# Some features can be hidden away to GUEST, when project is private.
# (see ProjectFeature::PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT)
# This is the table for such features.
#
# e.g. `repository` feature has minimum requirement of GUEST,
# but a GUEST are prohibited from reading code if project is private.
#
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_guest_feature_access_and_non_private_project_only
:public | :enabled | :admin | 1
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
:public | :enabled | :non_member | 1
:public | :enabled | :anonymous | 1
:public | :private | :admin | 1
:public | :private | :reporter | 1
:public | :private | :guest | 1
:public | :private | :non_member | 0
:public | :private | :anonymous | 0
:public | :disabled | :reporter | 0
:public | :disabled | :guest | 0
:public | :disabled | :non_member | 0
:public | :disabled | :anonymous | 0
:internal | :enabled | :admin | 1
:internal | :enabled | :reporter | 1
:internal | :enabled | :guest | 1
:internal | :enabled | :non_member | 1
:internal | :enabled | :anonymous | 0
:internal | :private | :admin | 1
:internal | :private | :reporter | 1
:internal | :private | :guest | 1
:internal | :private | :non_member | 0
:internal | :private | :anonymous | 0
:internal | :disabled | :reporter | 0
:internal | :disabled | :guest | 0
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
:private | :private | :admin | 1
:private | :private | :reporter | 1
:private | :private | :guest | 0
:private | :private | :non_member | 0
:private | :private | :anonymous | 0
:private | :disabled | :reporter | 0
:private | :disabled | :guest | 0
:private | :disabled | :non_member | 0
:private | :disabled | :anonymous | 0
end
# :project_level, :issues_access_level, :merge_requests_access_level, :membership, :expected_count
def permission_table_for_milestone_access
:public | :enabled | :enabled | :admin | 1
:public | :enabled | :enabled | :reporter | 1
:public | :enabled | :enabled | :guest | 1
:public | :enabled | :enabled | :non_member | 1
:public | :enabled | :enabled | :anonymous | 1
:public | :enabled | :private | :admin | 1
:public | :enabled | :private | :reporter | 1
:public | :enabled | :private | :guest | 1
:public | :enabled | :private | :non_member | 1
:public | :enabled | :private | :anonymous | 1
:public | :enabled | :disabled | :admin | 1
:public | :enabled | :disabled | :reporter | 1
:public | :enabled | :disabled | :guest | 1
:public | :enabled | :disabled | :non_member | 1
:public | :enabled | :disabled | :anonymous | 1
:public | :private | :enabled | :admin | 1
:public | :private | :enabled | :reporter | 1
:public | :private | :enabled | :guest | 1
:public | :private | :enabled | :non_member | 1
:public | :private | :enabled | :anonymous | 1
:public | :private | :private | :admin | 1
:public | :private | :private | :reporter | 1
:public | :private | :private | :guest | 1
:public | :private | :private | :non_member | 0
:public | :private | :private | :anonymous | 0
:public | :private | :disabled | :admin | 1
:public | :private | :disabled | :reporter | 1
:public | :private | :disabled | :guest | 1
:public | :private | :disabled | :non_member | 0
:public | :private | :disabled | :anonymous | 0
:public | :disabled | :enabled | :admin | 1
:public | :disabled | :enabled | :reporter | 1
:public | :disabled | :enabled | :guest | 1
:public | :disabled | :enabled | :non_member | 1
:public | :disabled | :enabled | :anonymous | 1
:public | :disabled | :private | :admin | 1
:public | :disabled | :private | :reporter | 1
:public | :disabled | :private | :guest | 0
:public | :disabled | :private | :non_member | 0
:public | :disabled | :private | :anonymous | 0
:public | :disabled | :disabled | :reporter | 0
:public | :disabled | :disabled | :guest | 0
:public | :disabled | :disabled | :non_member | 0
:public | :disabled | :disabled | :anonymous | 0
:internal | :enabled | :enabled | :admin | 1
:internal | :enabled | :enabled | :reporter | 1
:internal | :enabled | :enabled | :guest | 1
:internal | :enabled | :enabled | :non_member | 1
:internal | :enabled | :enabled | :anonymous | 0
:internal | :enabled | :private | :admin | 1
:internal | :enabled | :private | :reporter | 1
:internal | :enabled | :private | :guest | 1
:internal | :enabled | :private | :non_member | 1
:internal | :enabled | :private | :anonymous | 0
:internal | :enabled | :disabled | :admin | 1
:internal | :enabled | :disabled | :reporter | 1
:internal | :enabled | :disabled | :guest | 1
:internal | :enabled | :disabled | :non_member | 1
:internal | :enabled | :disabled | :anonymous | 0
:internal | :private | :enabled | :admin | 1
:internal | :private | :enabled | :reporter | 1
:internal | :private | :enabled | :guest | 1
:internal | :private | :enabled | :non_member | 1
:internal | :private | :enabled | :anonymous | 0
:internal | :private | :private | :admin | 1
:internal | :private | :private | :reporter | 1
:internal | :private | :private | :guest | 1
:internal | :private | :private | :non_member | 0
:internal | :private | :private | :anonymous | 0
:internal | :private | :disabled | :admin | 1
:internal | :private | :disabled | :reporter | 1
:internal | :private | :disabled | :guest | 1
:internal | :private | :disabled | :non_member | 0
:internal | :private | :disabled | :anonymous | 0
:internal | :disabled | :enabled | :admin | 1
:internal | :disabled | :enabled | :reporter | 1
:internal | :disabled | :enabled | :guest | 1
:internal | :disabled | :enabled | :non_member | 1
:internal | :disabled | :enabled | :anonymous | 0
:internal | :disabled | :private | :admin | 1
:internal | :disabled | :private | :reporter | 1
:internal | :disabled | :private | :guest | 0
:internal | :disabled | :private | :non_member | 0
:internal | :disabled | :private | :anonymous | 0
:internal | :disabled | :disabled | :reporter | 0
:internal | :disabled | :disabled | :guest | 0
:internal | :disabled | :disabled | :non_member | 0
:internal | :disabled | :disabled | :anonymous | 0
:private | :private | :private | :admin | 1
:private | :private | :private | :reporter | 1
:private | :private | :private | :guest | 1
:private | :private | :private | :non_member | 0
:private | :private | :private | :anonymous | 0
:private | :private | :disabled | :admin | 1
:private | :private | :disabled | :reporter | 1
:private | :private | :disabled | :guest | 1
:private | :private | :disabled | :non_member | 0
:private | :private | :disabled | :anonymous | 0
:private | :disabled | :private | :admin | 1
:private | :disabled | :private | :reporter | 1
:private | :disabled | :private | :guest | 0
:private | :disabled | :private | :non_member | 0
:private | :disabled | :private | :anonymous | 0
:private | :disabled | :disabled | :reporter | 0
:private | :disabled | :disabled | :guest | 0
:private | :disabled | :disabled | :non_member | 0
:private | :disabled | :disabled | :anonymous | 0
end
# :project_level, :membership, :expected_count
def permission_table_for_project_access
:public | :reporter | 1
:public | :guest | 1
Loading
Loading
# frozen_string_literal: true
 
RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
include StubRequests
let(:chat_service) { described_class.new }
let(:webhook_url) { 'https://example.gitlab.com/' }
let(:webhook_url) { 'https://example.gitlab.com' }
 
def execute_with_options(options)
receive(:new).with(webhook_url, options)
receive(:new).with(webhook_url, options.merge(http_client: SlackService::Notifier::HTTPClient))
.and_return(double(:slack_service).as_null_object)
end
 
Loading
Loading
@@ -38,9 +40,13 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
 
let!(:stubbed_resolved_hostname) do
stub_full_request(webhook_url, method: :post).request_pattern.uri_pattern.to_s
end
it "notifies about #{event_type} events" do
chat_service.execute(data)
expect(WebMock).to have_requested(:post, webhook_url)
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname)
end
end
 
Loading
Loading
@@ -49,9 +55,13 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
 
let!(:stubbed_resolved_hostname) do
stub_full_request(webhook_url, method: :post).request_pattern.uri_pattern.to_s
end
it "notifies about #{event_type} events" do
chat_service.execute(data)
expect(WebMock).not_to have_requested(:post, webhook_url)
expect(WebMock).not_to have_requested(:post, stubbed_resolved_hostname)
end
end
 
Loading
Loading
@@ -66,6 +76,10 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
Gitlab::DataBuilder::Push.build_sample(project, user)
end
 
let!(:stubbed_resolved_hostname) do
stub_full_request(webhook_url, method: :post).request_pattern.uri_pattern.to_s
end
before do
allow(chat_service).to receive_messages(
project: project,
Loading
Loading
@@ -74,8 +88,6 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
webhook: webhook_url
)
 
WebMock.stub_request(:post, webhook_url)
issue_service = Issues::CreateService.new(project, user, issue_service_options)
@issue = issue_service.execute
@issues_sample_data = issue_service.hook_data(@issue, 'open')
Loading
Loading
@@ -107,25 +119,25 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
it "calls #{service_name} API for push events" do
chat_service.execute(data)
 
expect(WebMock).to have_requested(:post, webhook_url).once
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
 
it "calls #{service_name} API for issue events" do
chat_service.execute(@issues_sample_data)
 
expect(WebMock).to have_requested(:post, webhook_url).once
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
 
it "calls #{service_name} API for merge requests events" do
chat_service.execute(@merge_sample_data)
 
expect(WebMock).to have_requested(:post, webhook_url).once
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
 
it "calls #{service_name} API for wiki page events" do
chat_service.execute(@wiki_page_sample_data)
 
expect(WebMock).to have_requested(:post, webhook_url).once
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
 
it "calls #{service_name} API for deployment events" do
Loading
Loading
@@ -133,14 +145,14 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
 
chat_service.execute(deployment_event_data)
 
expect(WebMock).to have_requested(:post, webhook_url).once
expect(WebMock).to have_requested(:post, stubbed_resolved_hostname).once
end
 
it 'uses the username as an option for slack when configured' do
allow(chat_service).to receive(:username).and_return(username)
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, username: username)
.with(webhook_url, username: username, http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -151,7 +163,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
it 'uses the channel as an option when it is configured' do
allow(chat_service).to receive(:channel).and_return(channel)
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: channel)
.with(webhook_url, channel: channel, http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -163,7 +175,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.update(push_channel: "random")
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: "random")
.with(webhook_url, channel: "random", http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -175,7 +187,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.update(merge_request_channel: "random")
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: "random")
.with(webhook_url, channel: "random", http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -187,7 +199,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.update(issue_channel: "random")
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: "random")
.with(webhook_url, channel: "random", http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -219,7 +231,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
chat_service.update(wiki_page_channel: "random")
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: "random")
.with(webhook_url, channel: "random", http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -238,7 +250,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
note_data = Gitlab::DataBuilder::Note.build(issue_note, user)
 
expect(Slack::Notifier).to receive(:new)
.with(webhook_url, channel: "random")
.with(webhook_url, channel: "random", http_client: SlackService::Notifier::HTTPClient)
.and_return(
double(:slack_service).as_null_object
)
Loading
Loading
@@ -286,7 +298,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
webhook: webhook_url
)
 
WebMock.stub_request(:post, webhook_url)
stub_full_request(webhook_url, method: :post)
end
 
context 'on default branch' do
Loading
Loading
@@ -461,7 +473,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
webhook: webhook_url
)
 
WebMock.stub_request(:post, webhook_url)
stub_full_request(webhook_url, method: :post)
end
 
context 'when commit comment event executed' do
Loading
Loading
@@ -535,7 +547,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
webhook: webhook_url
)
 
WebMock.stub_request(:post, webhook_url)
stub_full_request(webhook_url, method: :post)
end
 
context 'with succeeded pipeline' do
Loading
Loading
# frozen_string_literal: true
shared_examples 'a request using Gitlab::UrlBlocker' do
# Written to test internal patches against 3rd party libraries
#
# Expects the following to be available in the example contexts:
#
# make_request(uri): Wraps the request we want to test goes through Gitlab::HTTP
# http_method: :get, :post etc
# url_blocked_error_class: Probably just Gitlab::HTTP::BlockedUrlError
include StubRequests
context 'when local requests are not allowed' do
it 'allows an external request with http' do
request_stub = stub_full_request('http://example.com', method: http_method, ip_address: '93.184.216.34')
make_request('http://example.com/')
expect(request_stub).to have_been_requested
end
it 'allows an external request with https' do
request_stub = stub_full_request('https://example.com', method: http_method, ip_address: '93.184.216.34')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
it 'raises error when it is a request that resolves to a local address' do
stub_full_request('https://example.com', method: http_method, ip_address: '172.16.0.0')
expect { make_request('https://example.com') }
.to raise_error(url_blocked_error_class,
"URL 'https://example.com' is blocked: Requests to the local network are not allowed")
end
it 'raises error when it is a request that resolves to a localhost address' do
stub_full_request('https://example.com', method: http_method, ip_address: '127.0.0.1')
expect { make_request('https://example.com') }
.to raise_error(url_blocked_error_class,
"URL 'https://example.com' is blocked: Requests to localhost are not allowed")
end
it 'raises error when it is a request to local address' do
expect { make_request('http://172.16.0.0') }
.to raise_error(url_blocked_error_class,
"URL 'http://172.16.0.0' is blocked: Requests to the local network are not allowed")
end
it 'raises error when it is a request to localhost address' do
expect { make_request('http://127.0.0.1') }
.to raise_error(url_blocked_error_class,
"URL 'http://127.0.0.1' is blocked: Requests to localhost are not allowed")
end
end
context 'when port different from URL scheme is used' do
it 'allows the request' do
request_stub = stub_full_request('https://example.com:8080', method: http_method, ip_address: '93.184.216.34')
make_request('https://example.com:8080/')
expect(request_stub).to have_been_requested
end
it 'raises error when it is a request to local address' do
expect { make_request('https://172.16.0.0:8080') }
.to raise_error(url_blocked_error_class,
"URL 'https://172.16.0.0:8080' is blocked: Requests to the local network are not allowed")
end
it 'raises error when it is a request to localhost address' do
expect { make_request('https://127.0.0.1:8080') }
.to raise_error(url_blocked_error_class,
"URL 'https://127.0.0.1:8080' is blocked: Requests to localhost are not allowed")
end
end
context 'when DNS rebinding protection is disabled' do
before do
stub_application_setting(dns_rebinding_protection_enabled: false)
end
it 'allows the request' do
request_stub = stub_request(http_method, 'https://example.com')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
end
context 'when http(s) proxy environment variable is set' do
before do
stub_env('https_proxy' => 'https://my.proxy')
end
it 'allows the request' do
request_stub = stub_request(http_method, 'https://example.com')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
end
context 'when local requests are allowed' do
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
end
it 'allows an external request' do
request_stub = stub_full_request('https://example.com', method: http_method, ip_address: '93.184.216.34')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
it 'allows an external request that resolves to a local address' do
request_stub = stub_full_request('https://example.com', method: http_method, ip_address: '172.16.0.0')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
it 'allows an external request that resolves to a localhost address' do
request_stub = stub_full_request('https://example.com', method: http_method, ip_address: '127.0.0.1')
make_request('https://example.com/')
expect(request_stub).to have_been_requested
end
it 'allows a local address request' do
request_stub = stub_request(http_method, 'http://172.16.0.0')
make_request('http://172.16.0.0')
expect(request_stub).to have_been_requested
end
it 'allows a localhost address request' do
request_stub = stub_request(http_method, 'http://127.0.0.1')
make_request('http://127.0.0.1')
expect(request_stub).to have_been_requested
end
end
end
Loading
Loading
@@ -3,6 +3,8 @@
require 'spec_helper'
 
describe 'projects/_home_panel' do
include ProjectForksHelper
context 'notifications' do
let(:project) { create(:project) }
 
Loading
Loading
@@ -144,4 +146,36 @@ describe 'projects/_home_panel' do
end
end
end
context 'forks' do
let(:source_project) { create(:project, :repository) }
let(:project) { fork_project(source_project) }
let(:user) { create(:user) }
before do
assign(:project, project)
allow(view).to receive(:current_user).and_return(user)
end
context 'user can read fork source' do
it 'shows the forked-from project' do
allow(view).to receive(:can?).with(user, :read_project, source_project).and_return(true)
render
expect(rendered).to have_content("Forked from #{source_project.full_name}")
end
end
context 'user cannot read fork source' do
it 'does not show the forked-from project' do
allow(view).to receive(:can?).with(user, :read_project, source_project).and_return(false)
render
expect(rendered).to have_content("Forked from an inaccessible project")
end
end
end
end
Loading
Loading
@@ -4,6 +4,7 @@ require 'spec_helper'
 
describe 'projects/edit' do
include Devise::Test::ControllerHelpers
include ProjectForksHelper
 
let(:project) { create(:project) }
let(:user) { create(:admin) }
Loading
Loading
@@ -26,4 +27,59 @@ describe 'projects/edit' do
expect(rendered).not_to have_content('Export project')
end
end
context 'forking' do
before do
assign(:project, project)
allow(view).to receive(:current_user).and_return(user)
end
context 'project is not a fork' do
it 'hides the remove fork relationship settings' do
render
expect(rendered).not_to have_content('Remove fork relationship')
end
end
context 'project is a fork' do
let(:source_project) { create(:project) }
let(:project) { fork_project(source_project) }
it 'shows the remove fork relationship settings to an authorized user' do
allow(view).to receive(:can?).with(user, :remove_fork_project, project).and_return(true)
render
expect(rendered).to have_content('Remove fork relationship')
end
it 'hides the fork relationship settings from an unauthorized user' do
allow(view).to receive(:can?).with(user, :remove_fork_project, project).and_return(false)
render
expect(rendered).not_to have_content('Remove fork relationship')
end
it 'hides the fork source from an unauthorized user' do
allow(view).to receive(:can?).with(user, :read_project, source_project).and_return(false)
render
expect(rendered).to have_content('Remove fork relationship')
expect(rendered).not_to have_content(source_project.full_name)
end
it 'shows the fork source to an authorized user' do
allow(view).to receive(:can?).with(user, :read_project, source_project).and_return(true)
render
expect(rendered).to have_content('Remove fork relationship')
expect(rendered).to have_content(source_project.full_name)
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment