summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/blob/openapi/index.js6
-rw-r--r--config/application.rb1
-rw-r--r--doc/user/packages/maven_repository/index.md2
-rw-r--r--lib/api/entities/project.rb4
-rw-r--r--lib/gitlab/regex.rb2
-rw-r--r--lib/gitlab/slash_commands/deploy.rb12
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb51
-rw-r--r--spec/lib/api/entities/project_spec.rb22
-rw-r--r--spec/lib/gitlab/regex_spec.rb13
-rw-r--r--spec/lib/gitlab/slash_commands/deploy_spec.rb59
-rw-r--r--spec/models/packages/package_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb2
12 files changed, 168 insertions, 8 deletions
diff --git a/app/assets/javascripts/blob/openapi/index.js b/app/assets/javascripts/blob/openapi/index.js
index cb251274b18..b19cc19cb8c 100644
--- a/app/assets/javascripts/blob/openapi/index.js
+++ b/app/assets/javascripts/blob/openapi/index.js
@@ -1,5 +1,6 @@
import { SwaggerUIBundle } from 'swagger-ui-dist';
import createFlash from '~/flash';
+import { removeParams, updateHistory } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
export default () => {
@@ -7,9 +8,14 @@ export default () => {
Promise.all([import(/* webpackChunkName: 'openapi' */ 'swagger-ui-dist/swagger-ui.css')])
.then(() => {
+ // Temporary fix to prevent an XSS attack due to "useUnsafeMarkdown"
+ // Once we upgrade Swagger to "4.0.0", we can safely remove this as it will be deprecated
+ // Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/339696
+ updateHistory({ url: removeParams(['useUnsafeMarkdown']), replace: true });
SwaggerUIBundle({
url: el.dataset.endpoint,
dom_id: '#js-openapi-viewer',
+ useUnsafeMarkdown: false,
});
})
.catch((error) => {
diff --git a/config/application.rb b/config/application.rb
index dde1eae30e7..f64e5c998eb 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -411,6 +411,7 @@ module Gitlab
config.cache_store = :redis_cache_store, Gitlab::Redis::Cache.active_support_config
config.active_job.queue_adapter = :sidekiq
+ config.active_job.logger = nil
config.action_mailer.deliver_later_queue_name = :mailers
# This is needed for gitlab-shell
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index 1ca4bb2759d..6646f18e6fe 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -806,7 +806,7 @@ When the pipeline is successful, the package is created.
The version string is validated by using the following regex.
```ruby
-\A(\.?[\w\+-]+\.?)+\z
+\A(?!.*\.\.)[\w+.-]+\z
```
You can play around with the regex and try your version strings on [this regular expression editor](https://rubular.com/r/rrLQqUXjfKEoL6).
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index e3f1e90b80f..662ca59852e 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -55,7 +55,9 @@ module API
expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
expose(:container_registry_enabled) { |project, options| project.feature_available?(:container_registry, options[:current_user]) }
expose :service_desk_enabled
- expose :service_desk_address
+ expose :service_desk_address, if: -> (project, options) do
+ Ability.allowed?(options[:current_user], :admin_issue, project)
+ end
expose(:can_create_merge_request_in) do |project, options|
Ability.allowed?(options[:current_user], :create_merge_request_in, project)
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 8b2f786a91a..904fc744c6b 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -57,7 +57,7 @@ module Gitlab
end
def maven_version_regex
- @maven_version_regex ||= /\A(\.?[\w\+-]+\.?)+\z/.freeze
+ @maven_version_regex ||= /\A(?!.*\.\.)[\w+.-]+\z/.freeze
end
def maven_app_group_regex
diff --git a/lib/gitlab/slash_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb
index 157d924f99f..9fcefd99f81 100644
--- a/lib/gitlab/slash_commands/deploy.rb
+++ b/lib/gitlab/slash_commands/deploy.rb
@@ -3,8 +3,18 @@
module Gitlab
module SlashCommands
class Deploy < BaseCommand
+ DEPLOY_REGEX = /\Adeploy\s/.freeze
+
def self.match(text)
- /\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
+ return unless text&.match?(DEPLOY_REGEX)
+
+ from, _, to = text.sub(DEPLOY_REGEX, '').rpartition(/\sto+\s/)
+ return if from.blank? || to.blank?
+
+ {
+ from: from.strip,
+ to: to.strip
+ }
end
def self.help_message
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 8281e82959b..9d05c985af1 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe 'File blob', :js do
let(:project) { create(:project, :public, :repository) }
- def visit_blob(path, anchor: nil, ref: 'master')
- visit project_blob_path(project, File.join(ref, path), anchor: anchor)
+ def visit_blob(path, anchor: nil, ref: 'master', **additional_args)
+ visit project_blob_path(project, File.join(ref, path), anchor: anchor, **additional_args)
wait_for_requests
end
@@ -1501,6 +1501,53 @@ RSpec.describe 'File blob', :js do
end
end
end
+
+ context 'openapi.yml' do
+ before do
+ file_name = 'openapi.yml'
+
+ create_file(file_name, '
+ swagger: \'2.0\'
+ info:
+ title: Classic API Resource Documentation
+ description: |
+ <div class="foo-bar" style="background-color: red;" data-foo-bar="baz">
+ <h1>Swagger API documentation</h1>
+ </div>
+ version: production
+ basePath: /JSSResource/
+ produces:
+ - application/xml
+ - application/json
+ consumes:
+ - application/xml
+ - application/json
+ security:
+ - basicAuth: []
+ paths:
+ /accounts:
+ get:
+ responses:
+ \'200\':
+ description: No response was specified
+ tags:
+ - accounts
+ operationId: findAccounts
+ summary: Finds all accounts
+ ')
+ visit_blob(file_name, useUnsafeMarkdown: '1')
+ click_button('Display rendered file')
+
+ wait_for_requests
+ end
+
+ it 'removes `style`, `class`, and `data-*`` attributes from HTML' do
+ expect(page).to have_css('h1', text: 'Swagger API documentation')
+ expect(page).not_to have_css('.foo-bar')
+ expect(page).not_to have_css('[style="background-color: red;"]')
+ expect(page).not_to have_css('[data-foo-bar="baz"]')
+ end
+ end
end
end
diff --git a/spec/lib/api/entities/project_spec.rb b/spec/lib/api/entities/project_spec.rb
index 8d1c3aa878d..6b542278fa6 100644
--- a/spec/lib/api/entities/project_spec.rb
+++ b/spec/lib/api/entities/project_spec.rb
@@ -13,6 +13,28 @@ RSpec.describe ::API::Entities::Project do
subject(:json) { entity.as_json }
+ describe '.service_desk_address' do
+ before do
+ allow(project).to receive(:service_desk_enabled?).and_return(true)
+ end
+
+ context 'when a user can admin issues' do
+ before do
+ project.add_reporter(current_user)
+ end
+
+ it 'is present' do
+ expect(json[:service_desk_address]).to be_present
+ end
+ end
+
+ context 'when a user can not admin project' do
+ it 'is empty' do
+ expect(json[:service_desk_address]).to be_nil
+ end
+ end
+ end
+
describe '.shared_with_groups' do
let(:group) { create(:group, :private) }
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 9514654204b..05f1c88a6ab 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -344,6 +344,18 @@ RSpec.describe Gitlab::Regex do
describe '.maven_version_regex' do
subject { described_class.maven_version_regex }
+ it 'has no ReDoS issues with long strings' do
+ Timeout.timeout(5) do
+ expect(subject).to match("aaaaaaaa.aaaaaaaaa+aa-111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111")
+ end
+ end
+
+ it 'has no ReDos issues with long strings ending with an exclamation mark' do
+ Timeout.timeout(5) do
+ expect(subject).not_to match('a' * 50000 + '!')
+ end
+ end
+
it { is_expected.to match('0')}
it { is_expected.to match('1') }
it { is_expected.to match('03') }
@@ -364,6 +376,7 @@ RSpec.describe Gitlab::Regex do
it { is_expected.to match('703220b4e2cea9592caeb9f3013f6b1e5335c293') }
it { is_expected.to match('RELEASE') }
it { is_expected.not_to match('..1.2.3') }
+ it { is_expected.not_to match('1.2.3..beta') }
it { is_expected.not_to match(' 1.2.3') }
it { is_expected.not_to match("1.2.3 \r\t") }
it { is_expected.not_to match("\r\t 1.2.3") }
diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb
index 36f47c711bc..71fca1e1fc8 100644
--- a/spec/lib/gitlab/slash_commands/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb
@@ -109,6 +109,21 @@ RSpec.describe Gitlab::SlashCommands::Deploy do
end
end
end
+
+ context 'with extra spaces in the deploy command' do
+ let(:regex_match) { described_class.match('deploy staging to production ') }
+
+ before do
+ create(:ci_build, :manual, pipeline: pipeline, name: 'production', environment: 'production')
+ create(:ci_build, :manual, pipeline: pipeline, name: 'not prod', environment: 'not prod')
+ end
+
+ it 'deploys to production' do
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
+ expect(subject[:response_type]).to be(:in_channel)
+ end
+ end
end
end
@@ -119,5 +134,49 @@ RSpec.describe Gitlab::SlashCommands::Deploy do
expect(match[:from]).to eq('staging')
expect(match[:to]).to eq('production')
end
+
+ it 'matches the environment with spaces in it' do
+ match = described_class.match('deploy staging env to production env')
+
+ expect(match[:from]).to eq('staging env')
+ expect(match[:to]).to eq('production env')
+ end
+
+ it 'matches the environment name with surrounding spaces' do
+ match = described_class.match('deploy staging to production ')
+
+ # The extra spaces are stripped later in the code
+ expect(match[:from]).to eq('staging')
+ expect(match[:to]).to eq('production')
+ end
+
+ it 'returns nil for text that is not a deploy command' do
+ match = described_class.match('foo bar')
+
+ expect(match).to be_nil
+ end
+
+ it 'returns nil for a partial command' do
+ match = described_class.match('deploy staging to ')
+
+ expect(match).to be_nil
+ end
+
+ context 'with ReDoS attempts' do
+ def duration_for(&block)
+ start = Time.zone.now
+ yield if block_given?
+ Time.zone.now - start
+ end
+
+ it 'has smaller than linear execution time growth with a malformed "to"' do
+ Timeout.timeout(3.seconds) do
+ sample1 = duration_for { described_class.match("deploy abc t" + "o" * 1000 + "X") }
+ sample2 = duration_for { described_class.match("deploy abc t" + "o" * 4000 + "X") }
+
+ expect((sample2 / sample1) < 4).to be_truthy
+ end
+ end
+ end
end
end
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 6ee5219819c..44ba6e0e2fd 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -289,7 +289,6 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.to allow_value('1.1-beta-2').for(:version) }
it { is_expected.to allow_value('1.2-SNAPSHOT').for(:version) }
it { is_expected.to allow_value('12.1.2-2-1').for(:version) }
- it { is_expected.to allow_value('1.2.3..beta').for(:version) }
it { is_expected.to allow_value('1.2.3-beta').for(:version) }
it { is_expected.to allow_value('10.2.3-beta').for(:version) }
it { is_expected.to allow_value('2.0.0.v200706041905-7C78EK9E_EkMNfNOd2d8qq').for(:version) }
@@ -297,6 +296,7 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.to allow_value('703220b4e2cea9592caeb9f3013f6b1e5335c293').for(:version) }
it { is_expected.to allow_value('RELEASE').for(:version) }
it { is_expected.not_to allow_value('..1.2.3').for(:version) }
+ it { is_expected.not_to allow_value('1.2.3..beta').for(:version) }
it { is_expected.not_to allow_value(' 1.2.3').for(:version) }
it { is_expected.not_to allow_value("1.2.3 \r\t").for(:version) }
it { is_expected.not_to allow_value("\r\t 1.2.3").for(:version) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 4f84e6f2562..cc546cbcda1 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -225,7 +225,7 @@ RSpec.describe API::Projects do
create(:project, :public, group: create(:group))
end
- it_behaves_like 'projects response without N + 1 queries', 0 do
+ it_behaves_like 'projects response without N + 1 queries', 1 do
let(:current_user) { user }
let(:additional_project) { create(:project, :public, group: create(:group)) }
end