diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/ci/build/policy/refs.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/ci/config/entry/policy.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/config/entry/validators.rb | 16 | ||||
-rw-r--r-- | lib/gitlab/git/wiki.rb | 10 | ||||
-rw-r--r-- | lib/gitlab/gitaly_client/wiki_service.rb | 9 | ||||
-rw-r--r-- | lib/gitlab/graphql/query_analyzers/log_query_complexity.rb | 18 | ||||
-rw-r--r-- | lib/gitlab/prometheus_client.rb | 32 | ||||
-rw-r--r-- | lib/gitlab/untrusted_regexp/ruby_syntax.rb | 39 |
8 files changed, 105 insertions, 25 deletions
diff --git a/lib/gitlab/ci/build/policy/refs.rb b/lib/gitlab/ci/build/policy/refs.rb index 360424bec11..c3005303fd8 100644 --- a/lib/gitlab/ci/build/policy/refs.rb +++ b/lib/gitlab/ci/build/policy/refs.rb @@ -35,7 +35,7 @@ module Gitlab # patterns can be matched only when branch or tag is used # the pattern matching does not work for merge requests pipelines if pipeline.branch? || pipeline.tag? - if regexp = Gitlab::UntrustedRegexp::RubySyntax.fabricate(pattern) + if regexp = Gitlab::UntrustedRegexp::RubySyntax.fabricate(pattern, fallback: true) regexp.match?(pipeline.ref) else pattern == pipeline.ref diff --git a/lib/gitlab/ci/config/entry/policy.rb b/lib/gitlab/ci/config/entry/policy.rb index adc3660d950..7b14218d3ea 100644 --- a/lib/gitlab/ci/config/entry/policy.rb +++ b/lib/gitlab/ci/config/entry/policy.rb @@ -17,7 +17,7 @@ module Gitlab include ::Gitlab::Config::Entry::Validatable validations do - validates :config, array_of_strings_or_regexps: true + validates :config, array_of_strings_or_regexps_with_fallback: true end def value @@ -38,7 +38,7 @@ module Gitlab validate :variables_expressions_syntax with_options allow_nil: true do - validates :refs, array_of_strings_or_regexps: true + validates :refs, array_of_strings_or_regexps_with_fallback: true validates :kubernetes, allowed_values: %w[active] validates :variables, array_of_strings: true validates :changes, array_of_strings: true diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb index d0ee94370ba..746fe83f90f 100644 --- a/lib/gitlab/config/entry/validators.rb +++ b/lib/gitlab/config/entry/validators.rb @@ -129,6 +129,12 @@ module Gitlab end end + protected + + def fallback + false + end + private def matches_syntax?(value) @@ -137,7 +143,7 @@ module Gitlab def validate_regexp(value) matches_syntax?(value) && - Gitlab::UntrustedRegexp::RubySyntax.valid?(value) + Gitlab::UntrustedRegexp::RubySyntax.valid?(value, fallback: fallback) end end @@ -162,6 +168,14 @@ module Gitlab end end + class ArrayOfStringsOrRegexpsWithFallbackValidator < ArrayOfStringsOrRegexpsValidator + protected + + def fallback + true + end + end + class ArrayOfStringsOrStringValidator < RegexpValidator def validate_each(record, attribute, value) unless validate_array_of_strings_or_string(value) diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb index c43331bed60..a0dd4a24363 100644 --- a/lib/gitlab/git/wiki.rb +++ b/lib/gitlab/git/wiki.rb @@ -86,9 +86,9 @@ module Gitlab end end - def pages(limit: 0) + def pages(limit: 0, sort: nil, direction_desc: false) wrapped_gitaly_errors do - gitaly_get_all_pages(limit: limit) + gitaly_get_all_pages(limit: limit, sort: sort, direction_desc: direction_desc) end end @@ -168,8 +168,10 @@ module Gitlab Gitlab::Git::WikiFile.new(wiki_file) end - def gitaly_get_all_pages(limit: 0) - gitaly_wiki_client.get_all_pages(limit: limit).map do |wiki_page, version| + def gitaly_get_all_pages(limit: 0, sort: nil, direction_desc: false) + gitaly_wiki_client.get_all_pages( + limit: limit, sort: sort, direction_desc: direction_desc + ).map do |wiki_page, version| Gitlab::Git::WikiPage.new(wiki_page, version) end end diff --git a/lib/gitlab/gitaly_client/wiki_service.rb b/lib/gitlab/gitaly_client/wiki_service.rb index 15c9463e2f2..e036cdcd800 100644 --- a/lib/gitlab/gitaly_client/wiki_service.rb +++ b/lib/gitlab/gitaly_client/wiki_service.rb @@ -87,8 +87,13 @@ module Gitlab wiki_page_from_iterator(response) end - def get_all_pages(limit: 0) - request = Gitaly::WikiGetAllPagesRequest.new(repository: @gitaly_repo, limit: limit) + def get_all_pages(limit: 0, sort: nil, direction_desc: false) + sort_value = Gitaly::WikiGetAllPagesRequest::SortBy.resolve(sort.to_s.upcase.to_sym) + + params = { repository: @gitaly_repo, limit: limit, direction_desc: direction_desc } + params[:sort] = sort_value if sort_value + + request = Gitaly::WikiGetAllPagesRequest.new(params) response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_all_pages, request, timeout: GitalyClient.medium_timeout) pages = [] diff --git a/lib/gitlab/graphql/query_analyzers/log_query_complexity.rb b/lib/gitlab/graphql/query_analyzers/log_query_complexity.rb new file mode 100644 index 00000000000..95db130dbfc --- /dev/null +++ b/lib/gitlab/graphql/query_analyzers/log_query_complexity.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Gitlab + module Graphql + module QueryAnalyzers + class LogQueryComplexity + class << self + def analyzer + GraphQL::Analysis::QueryComplexity.new do |query, complexity| + # temporary until https://gitlab.com/gitlab-org/gitlab-ce/issues/59587 + Rails.logger.info("[GraphQL Query Complexity] #{complexity} | admin? #{query.context[:current_user]&.admin?}") + end + end + end + end + end + end +end diff --git a/lib/gitlab/prometheus_client.rb b/lib/gitlab/prometheus_client.rb index 45828c77a33..b4de7cd2bce 100644 --- a/lib/gitlab/prometheus_client.rb +++ b/lib/gitlab/prometheus_client.rb @@ -6,6 +6,14 @@ module Gitlab Error = Class.new(StandardError) QueryError = Class.new(Gitlab::PrometheusClient::Error) + # Target number of data points for `query_range`. + # Please don't exceed the limit of 11000 data points + # See https://github.com/prometheus/prometheus/blob/91306bdf24f5395e2601773316945a478b4b263d/web/api/v1/api.go#L347 + QUERY_RANGE_DATA_POINTS = 600 + + # Minimal value of the `step` parameter for `query_range` in seconds. + QUERY_RANGE_MIN_STEP = 60 + attr_reader :rest_client, :headers def initialize(rest_client) @@ -23,12 +31,18 @@ module Gitlab end def query_range(query, start: 8.hours.ago, stop: Time.now) + start = start.to_f + stop = stop.to_f + step = self.class.compute_step(start, stop) + get_result('matrix') do - json_api_get('query_range', - query: query, - start: start.to_f, - end: stop.to_f, - step: 1.minute.to_i) + json_api_get( + 'query_range', + query: query, + start: start, + end: stop, + step: step + ) end end @@ -40,6 +54,14 @@ module Gitlab json_api_get('series', 'match': matches, start: start.to_f, end: stop.to_f) end + def self.compute_step(start, stop) + diff = stop - start + + step = (diff / QUERY_RANGE_DATA_POINTS).ceil + + [QUERY_RANGE_MIN_STEP, step].max + end + private def json_api_get(type, args = {}) diff --git a/lib/gitlab/untrusted_regexp/ruby_syntax.rb b/lib/gitlab/untrusted_regexp/ruby_syntax.rb index 91f300f97d0..6adf119aa75 100644 --- a/lib/gitlab/untrusted_regexp/ruby_syntax.rb +++ b/lib/gitlab/untrusted_regexp/ruby_syntax.rb @@ -6,7 +6,7 @@ module Gitlab # and converts that to RE2 representation: # /<regexp>/<flags> class RubySyntax - PATTERN = %r{^/(?<regexp>.+)/(?<flags>[ismU]*)$}.freeze + PATTERN = %r{^/(?<regexp>.*)/(?<flags>[ismU]*)$}.freeze # Checks if pattern matches a regexp pattern # but does not enforce it's validity @@ -16,28 +16,47 @@ module Gitlab # The regexp can match the pattern `/.../`, but may not be fabricatable: # it can be invalid or incomplete: `/match ( string/` - def self.valid?(pattern) - !!self.fabricate(pattern) + def self.valid?(pattern, fallback: false) + !!self.fabricate(pattern, fallback: fallback) end - def self.fabricate(pattern) - self.fabricate!(pattern) + def self.fabricate(pattern, fallback: false) + self.fabricate!(pattern, fallback: fallback) rescue RegexpError nil end - def self.fabricate!(pattern) + def self.fabricate!(pattern, fallback: false) raise RegexpError, 'Pattern is not string!' unless pattern.is_a?(String) matches = pattern.match(PATTERN) raise RegexpError, 'Invalid regular expression!' if matches.nil? - expression = matches[:regexp] - flags = matches[:flags] - expression.prepend("(?#{flags})") if flags.present? + begin + create_untrusted_regexp(matches[:regexp], matches[:flags]) + rescue RegexpError + raise unless fallback && + Feature.enabled?(:allow_unsafe_ruby_regexp, default_enabled: false) - UntrustedRegexp.new(expression, multiline: false) + create_ruby_regexp(matches[:regexp], matches[:flags]) + end end + + def self.create_untrusted_regexp(pattern, flags) + pattern.prepend("(?#{flags})") if flags.present? + + UntrustedRegexp.new(pattern, multiline: false) + end + private_class_method :create_untrusted_regexp + + def self.create_ruby_regexp(pattern, flags) + options = 0 + options += Regexp::IGNORECASE if flags&.include?('i') + options += Regexp::MULTILINE if flags&.include?('m') + + Regexp.new(pattern, options) + end + private_class_method :create_ruby_regexp end end end |