Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-31 03:00:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-31 03:00:32 +0300
commit1153e17b2d34c50834251038269ac11f18219bdf (patch)
tree20b80086422da0d03cb3a1af0300858570c35e7e /spec
parentd111c2d301f43d0b6de98f47da39d2b107ce17a1 (diff)
Add latest changes from gitlab-org/security/gitlab@14-9-stable-ee
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb18
-rw-r--r--spec/controllers/projects/mirrors_controller_spec.rb1
-rw-r--r--spec/features/markdown/kroki_spec.rb55
-rw-r--r--spec/frontend/behaviors/components/diagram_performance_warning_spec.js40
-rw-r--r--spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb70
-rw-r--r--spec/lib/banzai/filter/kroki_filter_spec.rb12
-rw-r--r--spec/lib/banzai/reference_redactor_spec.rb2
-rw-r--r--spec/lib/gitlab/error_tracking/processor/sanitize_error_message_processor_spec.rb53
-rw-r--r--spec/lib/gitlab/error_tracking_spec.rb56
-rw-r--r--spec/lib/gitlab/exception_log_formatter_spec.rb8
-rw-r--r--spec/lib/gitlab/sanitizers/exception_message_spec.rb54
-rw-r--r--spec/models/integrations/asana_spec.rb36
-rw-r--r--spec/models/ssh_host_key_spec.rb45
-rw-r--r--spec/policies/project_policy_spec.rb161
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb8
-rw-r--r--spec/support/shared_examples/policies/project_policy_shared_examples.rb13
16 files changed, 600 insertions, 32 deletions
diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
index 3c650988b4f..a061a14c7b1 100644
--- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
@@ -186,6 +186,7 @@ RSpec.describe Projects::MergeRequests::CreationsController do
it 'fetches the commit if a user has access' do
expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true }
+ expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once)
get :branch_to,
params: {
@@ -199,8 +200,25 @@ RSpec.describe Projects::MergeRequests::CreationsController do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'does not load the commit when the user cannot create_merge_request_in' do
+ expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true }
+ expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { false }.at_least(:once)
+
+ get :branch_to,
+ params: {
+ namespace_id: fork_project.namespace,
+ project_id: fork_project,
+ target_project_id: project.id,
+ ref: 'master'
+ }
+
+ expect(assigns(:commit)).to be_nil
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
it 'does not load the commit when the user cannot read the project' do
expect(Ability).to receive(:allowed?).with(user, :read_project, project) { false }
+ expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once)
get :branch_to,
params: {
diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb
index 7bc86d7c583..686effd799e 100644
--- a/spec/controllers/projects/mirrors_controller_spec.rb
+++ b/spec/controllers/projects/mirrors_controller_spec.rb
@@ -177,6 +177,7 @@ RSpec.describe Projects::MirrorsController do
INVALID
git@example.com:foo/bar.git
ssh://git@example.com:foo/bar.git
+ ssh://127.0.0.1/foo/bar.git
].each do |url|
it "returns an error with a 400 response for URL #{url.inspect}" do
do_get(project, url)
diff --git a/spec/features/markdown/kroki_spec.rb b/spec/features/markdown/kroki_spec.rb
new file mode 100644
index 00000000000..f02f5d44244
--- /dev/null
+++ b/spec/features/markdown/kroki_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'kroki rendering', :js do
+ let_it_be(:project) { create(:project, :public) }
+
+ before do
+ stub_application_setting(kroki_enabled: true, kroki_url: 'http://localhost:8000')
+ end
+
+ it 'shows kroki image' do
+ plain_text = 'This text length is ignored. ' * 300
+
+ description = <<~KROKI
+ #{plain_text}
+ ```plantuml
+ A -> A: T
+ ```
+ KROKI
+
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ within('.description') do
+ expect(page).to have_css('img')
+ expect(page).not_to have_text 'Warning: Displaying this diagram might cause performance issues on this page.'
+ end
+ end
+
+ it 'hides kroki image and shows warning alert when kroki source size is large' do
+ plantuml_text = 'A -> A: T ' * 300
+
+ description = <<~KROKI
+ ```plantuml
+ #{plantuml_text}
+ ```
+ KROKI
+
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ within('.description') do
+ expect(page).not_to have_css('img')
+ expect(page).to have_text 'Warning: Displaying this diagram might cause performance issues on this page.'
+
+ click_button 'Display'
+
+ expect(page).to have_css('img')
+ expect(page).not_to have_text 'Warning: Displaying this diagram might cause performance issues on this page.'
+ end
+ end
+end
diff --git a/spec/frontend/behaviors/components/diagram_performance_warning_spec.js b/spec/frontend/behaviors/components/diagram_performance_warning_spec.js
new file mode 100644
index 00000000000..c58c2bc55a9
--- /dev/null
+++ b/spec/frontend/behaviors/components/diagram_performance_warning_spec.js
@@ -0,0 +1,40 @@
+import { GlAlert } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import DiagramPerformanceWarning from '~/behaviors/components/diagram_performance_warning.vue';
+
+describe('DiagramPerformanceWarning component', () => {
+ let wrapper;
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ beforeEach(() => {
+ wrapper = shallowMount(DiagramPerformanceWarning);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders warning alert with button', () => {
+ expect(findAlert().props()).toMatchObject({
+ primaryButtonText: DiagramPerformanceWarning.i18n.buttonText,
+ variant: 'warning',
+ });
+ });
+
+ it('renders warning message', () => {
+ expect(findAlert().text()).toBe(DiagramPerformanceWarning.i18n.bodyText);
+ });
+
+ it('emits event when closing alert', () => {
+ findAlert().vm.$emit('dismiss');
+
+ expect(wrapper.emitted('closeAlert')).toEqual([[]]);
+ });
+
+ it('emits event when accepting alert', () => {
+ findAlert().vm.$emit('primaryAction');
+
+ expect(wrapper.emitted('showImage')).toEqual([[]]);
+ });
+});
diff --git a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
index ccc861baae5..66a5f0277fb 100644
--- a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
let(:current_user) { reporter }
- before_all do
+ before do
project.add_guest(guest)
project.add_reporter(reporter)
end
@@ -20,13 +20,8 @@ RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
expect(described_class).to have_nullable_graphql_type(::Types::Ci::AnalyticsType)
end
- def resolve_statistics(project, args)
- ctx = { current_user: current_user }
- resolve(described_class, obj: project, args: args, ctx: ctx)
- end
-
- describe '#resolve' do
- it 'returns the pipelines statistics for a given project' do
+ shared_examples 'returns the pipelines statistics for a given project' do
+ it do
result = resolve_statistics(project, {})
expect(result.keys).to contain_exactly(
:week_pipelines_labels,
@@ -42,14 +37,67 @@ RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do
:pipeline_times_values
)
end
+ end
+
+ shared_examples 'it returns nils' do
+ it do
+ result = resolve_statistics(project, {})
+
+ expect(result).to be_nil
+ end
+ end
+
+ def resolve_statistics(project, args)
+ ctx = { current_user: current_user }
+ resolve(described_class, obj: project, args: args, ctx: ctx)
+ end
+
+ describe '#resolve' do
+ it_behaves_like 'returns the pipelines statistics for a given project'
context 'when the user does not have access to the CI/CD analytics data' do
let(:current_user) { guest }
- it 'returns nil' do
- result = resolve_statistics(project, {})
+ it_behaves_like 'it returns nils'
+ end
+
+ context 'when the project is public' do
+ let_it_be(:project) { create(:project, :public) }
+
+ context 'public pipelines are disabled' do
+ before do
+ project.update!(public_builds: false)
+ end
+
+ context 'user is not a member' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'it returns nils'
+ end
+
+ context 'user is a guest' do
+ let(:current_user) { guest }
+
+ it_behaves_like 'it returns nils'
+ end
+
+ context 'user is a reporter or above' do
+ let(:current_user) { reporter }
+
+ it_behaves_like 'returns the pipelines statistics for a given project'
+ end
+ end
+
+ context 'public pipelines are enabled' do
+ before do
+ project.update!(public_builds: true)
+ end
+
+ context 'user is not a member' do
+ let(:current_user) { create(:user) }
- expect(result).to be_nil
+ it_behaves_like 'returns the pipelines statistics for a given project'
+ end
end
end
end
diff --git a/spec/lib/banzai/filter/kroki_filter_spec.rb b/spec/lib/banzai/filter/kroki_filter_spec.rb
index 57caba1d4d7..c9594ac702d 100644
--- a/spec/lib/banzai/filter/kroki_filter_spec.rb
+++ b/spec/lib/banzai/filter/kroki_filter_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Banzai::Filter::KrokiFilter do
stub_application_setting(kroki_enabled: true, kroki_url: "http://localhost:8000")
doc = filter("<pre lang='nomnoml'><code>[Pirate|eyeCount: Int|raid();pillage()|\n [beard]--[parrot]\n [beard]-:>[foul mouth]\n]</code></pre>")
- expect(doc.to_s).to eq '<img src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KzhUlCITkpNLEqJ1dWNLkgsKsoviUUSs7KLTssvzVHIzS8tyYjligUAMhEd0g==">'
+ expect(doc.to_s).to eq '<img class="js-render-kroki" src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KzhUlCITkpNLEqJ1dWNLkgsKsoviUUSs7KLTssvzVHIzS8tyYjligUAMhEd0g==">'
end
it 'replaces nomnoml pre tag with img tag if both kroki and plantuml are enabled' do
@@ -19,7 +19,7 @@ RSpec.describe Banzai::Filter::KrokiFilter do
plantuml_url: "http://localhost:8080")
doc = filter("<pre lang='nomnoml'><code>[Pirate|eyeCount: Int|raid();pillage()|\n [beard]--[parrot]\n [beard]-:>[foul mouth]\n]</code></pre>")
- expect(doc.to_s).to eq '<img src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KzhUlCITkpNLEqJ1dWNLkgsKsoviUUSs7KLTssvzVHIzS8tyYjligUAMhEd0g==">'
+ expect(doc.to_s).to eq '<img class="js-render-kroki" src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KzhUlCITkpNLEqJ1dWNLkgsKsoviUUSs7KLTssvzVHIzS8tyYjligUAMhEd0g==">'
end
it 'does not replace nomnoml pre tag with img tag if kroki is disabled' do
@@ -38,4 +38,12 @@ RSpec.describe Banzai::Filter::KrokiFilter do
expect(doc.to_s).to eq '<pre lang="plantuml"><code>Bob-&gt;Alice : hello</code></pre>'
end
+
+ it 'adds hidden attribute when content size is large' do
+ stub_application_setting(kroki_enabled: true, kroki_url: "http://localhost:8000")
+ text = '[Pirate|eyeCount: Int|raid();pillage()|\n [beard]--[parrot]\n [beard]-:>[foul mouth]\n]' * 25
+ doc = filter("<pre lang='nomnoml'><code>#{text}</code></pre>")
+
+ expect(doc.to_s).to eq '<img class="js-render-kroki" src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KyJyVNQiE5KTSxKidXVjS5ILCrKL4lFFrSyi07LL81RyM0vLckAysRGjxo8avCowaMGjxo8avCowaMGU8lgAE7mIdc=" hidden>'
+ end
end
diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb
index 45e14032a98..344b8988296 100644
--- a/spec/lib/banzai/reference_redactor_spec.rb
+++ b/spec/lib/banzai/reference_redactor_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Banzai::ReferenceRedactor do
end
context 'when data-original attribute provided' do
- let(:original_content) { '<code>foo</code>' }
+ let(:original_content) { '&lt;script&gt;alert(1);&lt;/script&gt;' }
it 'replaces redacted reference with original content' do
doc = Nokogiri::HTML.fragment("<a class='gfm' href='https://www.gitlab.com' data-reference-type='issue' data-original='#{original_content}'>bar</a>")
diff --git a/spec/lib/gitlab/error_tracking/processor/sanitize_error_message_processor_spec.rb b/spec/lib/gitlab/error_tracking/processor/sanitize_error_message_processor_spec.rb
new file mode 100644
index 00000000000..5ec73233e77
--- /dev/null
+++ b/spec/lib/gitlab/error_tracking/processor/sanitize_error_message_processor_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ErrorTracking::Processor::SanitizeErrorMessageProcessor, :sentry do
+ describe '.call' do
+ let(:exception) { StandardError.new('raw error') }
+ let(:result_hash) { described_class.call(event).to_hash }
+
+ shared_examples 'processes the exception' do
+ it 'cleans the exception message' do
+ expect(Gitlab::Sanitizers::ExceptionMessage).to receive(:clean).with('StandardError', 'raw error').and_return('cleaned')
+
+ expect(result_hash[:exception][:values].first).to include(
+ type: 'StandardError',
+ value: 'cleaned'
+ )
+ end
+ end
+
+ context 'with Raven event' do
+ let(:raven_required_options) do
+ {
+ configuration: Raven.configuration,
+ context: Raven.context,
+ breadcrumbs: Raven.breadcrumbs
+ }
+ end
+
+ let(:event) { Raven::Event.from_exception(exception, raven_required_options) }
+
+ it_behaves_like 'processes the exception'
+ end
+
+ context 'with Sentry event' do
+ let(:event) { Sentry.get_current_client.event_from_exception(exception) }
+
+ it_behaves_like 'processes the exception'
+ end
+
+ context 'with invalid event' do
+ let(:event) { instance_double('Sentry::Event', to_hash: { invalid: true }) }
+
+ it 'does nothing' do
+ extracted_exception = instance_double('Sentry::SingleExceptionInterface', value: nil)
+ allow(described_class).to receive(:extract_exceptions_from).and_return([extracted_exception])
+
+ expect(Gitlab::Sanitizers::ExceptionMessage).not_to receive(:clean)
+ expect(result_hash).to eq(invalid: true)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/error_tracking_spec.rb b/spec/lib/gitlab/error_tracking_spec.rb
index 936954fc1b6..1ade3a51c55 100644
--- a/spec/lib/gitlab/error_tracking_spec.rb
+++ b/spec/lib/gitlab/error_tracking_spec.rb
@@ -368,5 +368,61 @@ RSpec.describe Gitlab::ErrorTracking do
end
end
end
+
+ context 'when processing invalid URI exceptions' do
+ let(:invalid_uri) { 'http://foo:bar' }
+ let(:raven_exception_values) { raven_event['exception']['values'] }
+ let(:sentry_exception_values) { sentry_event.exception.to_hash[:values] }
+
+ context 'when the error is a URI::InvalidURIError' do
+ let(:exception) do
+ URI.parse(invalid_uri)
+ rescue URI::InvalidURIError => error
+ error
+ end
+
+ it 'filters the URI from the error message' do
+ track_exception
+
+ expect(raven_exception_values).to include(
+ hash_including(
+ 'type' => 'URI::InvalidURIError',
+ 'value' => 'bad URI(is not URI?): [FILTERED]'
+ )
+ )
+ expect(sentry_exception_values).to include(
+ hash_including(
+ type: 'URI::InvalidURIError',
+ value: 'bad URI(is not URI?): [FILTERED]'
+ )
+ )
+ end
+ end
+
+ context 'when the error is a Addressable::URI::InvalidURIError' do
+ let(:exception) do
+ Addressable::URI.parse(invalid_uri)
+ rescue Addressable::URI::InvalidURIError => error
+ error
+ end
+
+ it 'filters the URI from the error message' do
+ track_exception
+
+ expect(raven_exception_values).to include(
+ hash_including(
+ 'type' => 'Addressable::URI::InvalidURIError',
+ 'value' => 'Invalid port number: [FILTERED]'
+ )
+ )
+ expect(sentry_exception_values).to include(
+ hash_including(
+ type: 'Addressable::URI::InvalidURIError',
+ value: 'Invalid port number: [FILTERED]'
+ )
+ )
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/exception_log_formatter_spec.rb b/spec/lib/gitlab/exception_log_formatter_spec.rb
index beeeeb2b64c..7dda56f0bf5 100644
--- a/spec/lib/gitlab/exception_log_formatter_spec.rb
+++ b/spec/lib/gitlab/exception_log_formatter_spec.rb
@@ -22,6 +22,14 @@ RSpec.describe Gitlab::ExceptionLogFormatter do
expect(payload['exception.sql']).to be_nil
end
+ it 'cleans the exception message' do
+ expect(Gitlab::Sanitizers::ExceptionMessage).to receive(:clean).with('RuntimeError', 'bad request').and_return('cleaned')
+
+ described_class.format!(exception, payload)
+
+ expect(payload['exception.message']).to eq('cleaned')
+ end
+
context 'when exception is ActiveRecord::StatementInvalid' do
let(:exception) { ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1') }
diff --git a/spec/lib/gitlab/sanitizers/exception_message_spec.rb b/spec/lib/gitlab/sanitizers/exception_message_spec.rb
new file mode 100644
index 00000000000..8b54b353235
--- /dev/null
+++ b/spec/lib/gitlab/sanitizers/exception_message_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+RSpec.describe Gitlab::Sanitizers::ExceptionMessage do
+ describe '.clean' do
+ let(:exception_name) { exception.class.name }
+ let(:exception_message) { exception.message }
+
+ subject { described_class.clean(exception_name, exception_message) }
+
+ context 'when error is a URI::InvalidURIError' do
+ let(:exception) do
+ URI.parse('http://foo:bar')
+ rescue URI::InvalidURIError => error
+ error
+ end
+
+ it { is_expected.to eq('bad URI(is not URI?): [FILTERED]') }
+ end
+
+ context 'when error is an Addressable::URI::InvalidURIError' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:exception) do
+ Addressable::URI.parse(uri)
+ rescue Addressable::URI::InvalidURIError => error
+ error
+ end
+
+ where(:uri, :result) do
+ 'http://foo:bar' | 'Invalid port number: [FILTERED]'
+ 'http://foo:%eb' | 'Invalid encoding in port'
+ 'ht%0atp://foo' | 'Invalid scheme format: [FILTERED]'
+ 'http:' | 'Absolute URI missing hierarchical segment: [FILTERED]'
+ '::http' | 'Cannot assemble URI string with ambiguous path: [FILTERED]'
+ 'http://foo bar' | 'Invalid character in host: [FILTERED]'
+ end
+
+ with_them do
+ it { is_expected.to eq(result) }
+ end
+ end
+
+ context 'with any other exception' do
+ let(:exception) { StandardError.new('Error message: http://foo@bar:baz@ex:ample.com') }
+
+ it 'is not invoked and does nothing' do
+ is_expected.to eq('Error message: http://foo@bar:baz@ex:ample.com')
+ end
+ end
+ end
+end
diff --git a/spec/models/integrations/asana_spec.rb b/spec/models/integrations/asana_spec.rb
index b6602964182..43e876a4f47 100644
--- a/spec/models/integrations/asana_spec.rb
+++ b/spec/models/integrations/asana_spec.rb
@@ -20,11 +20,13 @@ RSpec.describe Integrations::Asana do
let(:gid) { "123456789ABCD" }
let(:asana_task) { double(::Asana::Resources::Task) }
let(:asana_integration) { described_class.new }
+ let(:ref) { 'main' }
+ let(:restrict_to_branch) { nil }
let(:data) do
{
object_kind: 'push',
- ref: 'master',
+ ref: ref,
user_name: user.name,
commits: [
{
@@ -40,16 +42,44 @@ RSpec.describe Integrations::Asana do
project: project,
project_id: project.id,
api_key: 'verySecret',
- restrict_to_branch: 'master'
+ restrict_to_branch: restrict_to_branch
)
end
subject(:execute_integration) { asana_integration.execute(data) }
+ context 'with restrict_to_branch' do
+ let(:restrict_to_branch) { 'feature-branch, main' }
+ let(:message) { 'fix #456789' }
+
+ context 'when ref is in scope of restriced branches' do
+ let(:ref) { 'main' }
+
+ it 'calls the Asana integration' do
+ expect(asana_task).to receive(:add_comment)
+ expect(asana_task).to receive(:update).with(completed: true)
+ expect(::Asana::Resources::Task).to receive(:find_by_id).with(anything, '456789').once.and_return(asana_task)
+
+ execute_integration
+ end
+ end
+
+ context 'when ref is not in scope of restricted branches' do
+ let(:ref) { 'mai' }
+
+ it 'does not call the Asana integration' do
+ expect(asana_task).not_to receive(:add_comment)
+ expect(::Asana::Resources::Task).not_to receive(:find_by_id)
+
+ execute_integration
+ end
+ end
+ end
+
context 'when creating a story' do
let(:message) { "Message from commit. related to ##{gid}" }
let(:expected_message) do
- "#{user.name} pushed to branch master of #{project.full_name} ( https://gitlab.com/ ): #{message}"
+ "#{user.name} pushed to branch main of #{project.full_name} ( https://gitlab.com/ ): #{message}"
end
it 'calls Asana integration to create a story' do
diff --git a/spec/models/ssh_host_key_spec.rb b/spec/models/ssh_host_key_spec.rb
index 4d729d5585f..4b756846598 100644
--- a/spec/models/ssh_host_key_spec.rb
+++ b/spec/models/ssh_host_key_spec.rb
@@ -4,7 +4,9 @@ require 'spec_helper'
RSpec.describe SshHostKey do
using RSpec::Parameterized::TableSyntax
+
include ReactiveCachingHelpers
+ include StubRequests
let(:key1) do
'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3UpyF2iLqy1d63M6k3jH1vuEnq/NWtE+o' \
@@ -35,6 +37,7 @@ RSpec.describe SshHostKey do
let(:extra) { known_hosts + "foo\nbar\n" }
let(:reversed) { known_hosts.lines.reverse.join }
+ let(:url) { 'ssh://example.com:2222' }
let(:compare_host_keys) { nil }
def stub_ssh_keyscan(args, status: true, stdout: "", stderr: "")
@@ -50,7 +53,7 @@ RSpec.describe SshHostKey do
let(:project) { build(:project) }
- subject(:ssh_host_key) { described_class.new(project: project, url: 'ssh://example.com:2222', compare_host_keys: compare_host_keys) }
+ subject(:ssh_host_key) { described_class.new(project: project, url: url, compare_host_keys: compare_host_keys) }
describe '.primary_key' do
it 'returns a symbol' do
@@ -191,5 +194,45 @@ RSpec.describe SshHostKey do
is_expected.to eq(error: 'Failed to detect SSH host keys')
end
end
+
+ context 'DNS rebinding protection enabled' do
+ before do
+ stub_application_setting(dns_rebinding_protection_enabled: true)
+ end
+
+ it 'sends an address as well as hostname to ssh-keyscan' do
+ stub_dns(url, ip_address: '1.2.3.4')
+
+ stdin = stub_ssh_keyscan(%w[-T 5 -p 2222 -f-])
+
+ cache
+
+ expect(stdin.string).to eq("1.2.3.4 example.com\n")
+ end
+ end
+ end
+
+ describe 'URL validation' do
+ let(:url) { 'ssh://127.0.0.1' }
+
+ context 'when local requests are not allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
+ end
+
+ it 'forbids scanning localhost' do
+ expect { ssh_host_key }.to raise_error(/Invalid URL/)
+ 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 'permits scanning localhost' do
+ expect(ssh_host_key.url.to_s).to eq('ssh://127.0.0.1:22')
+ end
+ end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 0da37fc5378..fb1c5874335 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -81,25 +81,62 @@ RSpec.describe ProjectPolicy do
context 'merge requests feature' do
let(:current_user) { owner }
+ let(:mr_permissions) do
+ [:create_merge_request_from, :read_merge_request, :update_merge_request,
+ :admin_merge_request, :create_merge_request_in]
+ end
it 'disallows all permissions when the feature is disabled' do
project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED)
- mr_permissions = [:create_merge_request_from, :read_merge_request,
- :update_merge_request, :admin_merge_request,
- :create_merge_request_in]
-
expect_disallowed(*mr_permissions)
end
+
+ context 'for a guest in a private project' do
+ let(:current_user) { guest }
+ let(:project) { private_project }
+
+ it 'disallows the guest from all merge request permissions' do
+ expect_disallowed(*mr_permissions)
+ end
+ end
end
- context 'for a guest in a private project' do
- let(:current_user) { guest }
- let(:project) { private_project }
+ context 'creating_merge_request_in' do
+ context 'when project is public' do
+ let(:project) { public_project }
+
+ context 'when the current_user is guest' do
+ let(:current_user) { guest }
+
+ it { is_expected.to be_allowed(:create_merge_request_in) }
+ end
+ end
+
+ context 'when project is internal' do
+ let(:project) { internal_project }
+
+ context 'when the current_user is guest' do
+ let(:current_user) { guest }
+
+ it { is_expected.to be_allowed(:create_merge_request_in) }
+ end
+ end
+
+ context 'when project is private' do
+ let(:project) { private_project }
+
+ context 'when the current_user is guest' do
+ let(:current_user) { guest }
+
+ it { is_expected.not_to be_allowed(:create_merge_request_in) }
+ end
+
+ context 'when the current_user is reporter or above' do
+ let(:current_user) { reporter }
- it 'disallows the guest from reading the merge request and merge request iid' do
- expect_disallowed(:read_merge_request)
- expect_disallowed(:read_merge_request_iid)
+ it { is_expected.to be_allowed(:create_merge_request_in) }
+ end
end
end
@@ -1316,6 +1353,110 @@ RSpec.describe ProjectPolicy do
end
end
+ describe 'read_ci_cd_analytics' do
+ context 'public project' do
+ let(:project) { create(:project, :public, :analytics_enabled) }
+ let(:current_user) { create(:user) }
+
+ context 'when public pipelines are disabled for the project' do
+ before do
+ project.update!(public_builds: false)
+ end
+
+ context 'project member' do
+ %w(guest reporter developer maintainer).each do |role|
+ context role do
+ before do
+ project.add_user(current_user, role.to_sym)
+ end
+
+ if role == 'guest'
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ else
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
+ end
+ end
+ end
+ end
+
+ context 'non member' do
+ let(:current_user) { non_member }
+
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+
+ context 'anonymous' do
+ let(:current_user) { anonymous }
+
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+ end
+
+ context 'when public pipelines are enabled for the project' do
+ before do
+ project.update!(public_builds: true)
+ end
+
+ context 'project member' do
+ %w(guest reporter developer maintainer).each do |role|
+ context role do
+ before do
+ project.add_user(current_user, role.to_sym)
+ end
+
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
+ end
+ end
+ end
+
+ context 'non member' do
+ let(:current_user) { non_member }
+
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
+ end
+
+ context 'anonymous' do
+ let(:current_user) { anonymous }
+
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
+ end
+ end
+ end
+
+ context 'private project' do
+ let(:project) { create(:project, :private, :analytics_enabled) }
+ let(:current_user) { create(:user) }
+
+ context 'project member' do
+ %w(guest reporter developer maintainer).each do |role|
+ context role do
+ before do
+ project.add_user(current_user, role.to_sym)
+ end
+
+ if role == 'guest'
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ else
+ it { is_expected.to be_allowed(:read_ci_cd_analytics) }
+ end
+ end
+ end
+ end
+
+ context 'non member' do
+ let(:current_user) { non_member }
+
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+
+ context 'anonymous' do
+ let(:current_user) { anonymous }
+
+ it { is_expected.to be_disallowed(:read_ci_cd_analytics) }
+ end
+ end
+ end
+
it_behaves_like 'Self-managed Core resource access tokens'
describe 'operations feature' do
diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
index 3641edc845a..a78953e8199 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -15,7 +15,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:base_guest_permissions) do
%i[
- award_emoji create_issue create_merge_request_in create_note
+ award_emoji create_issue create_note
create_project read_issue_board read_issue read_issue_iid read_issue_link
read_label read_planning_hierarchy read_issue_board_list read_milestone read_note read_project
read_project_for_iids read_project_member read_release read_snippet
@@ -26,12 +26,12 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:base_reporter_permissions) do
%i[
admin_issue admin_issue_link admin_label admin_issue_board_list
- create_snippet create_incident daily_statistics download_code
+ create_snippet create_incident daily_statistics create_merge_request_in download_code
download_wiki_code fork_project metrics_dashboard read_build
read_commit_status read_confidential_issues read_container_image
read_deployment read_environment read_merge_request
read_metrics_dashboard_annotation read_pipeline read_prometheus
- read_sentry_issue update_issue
+ read_sentry_issue update_issue create_merge_request_in
]
end
@@ -66,7 +66,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:public_permissions) do
%i[
- build_download_code build_read_container_image download_code
+ build_download_code build_read_container_image create_merge_request_in download_code
download_wiki_code fork_project read_commit_status read_container_image
read_pipeline read_release
]
diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
index a4243db6bc9..63e4d458ad4 100644
--- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb
+++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
@@ -107,6 +107,19 @@ RSpec.shared_examples 'deploy token does not get confused with user' do
end
RSpec.shared_examples 'project policies as guest' do
+ context 'abilities for public projects' do
+ let(:project) { public_project }
+ let(:current_user) { guest }
+
+ it do
+ expect_allowed(*guest_permissions)
+ expect_allowed(*public_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
+ end
+
context 'abilities for non-public projects' do
let(:project) { private_project }
let(:current_user) { guest }