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/data_builder/pipeline.rb | 2 | ||||
-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/authorize/authorize_field_service.rb | 31 | ||||
-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 | ||||
-rw-r--r-- | lib/gitlab/url_helpers.rb | 16 | ||||
-rw-r--r-- | lib/gitlab/workhorse.rb | 14 |
12 files changed, 150 insertions, 43 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/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb index 76c8b4ec5c2..fa06fb935f7 100644 --- a/lib/gitlab/data_builder/pipeline.rb +++ b/lib/gitlab/data_builder/pipeline.rb @@ -47,7 +47,7 @@ module Gitlab user: build.user.try(:hook_attrs), runner: build.runner && runner_hook_attrs(build.runner), artifacts_file: { - filename: build.artifacts_file.filename, + filename: build.artifacts_file&.filename, size: build.artifacts_size } } 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/authorize/authorize_field_service.rb b/lib/gitlab/graphql/authorize/authorize_field_service.rb index f3ca82ec697..8deff79fc84 100644 --- a/lib/gitlab/graphql/authorize/authorize_field_service.rb +++ b/lib/gitlab/graphql/authorize/authorize_field_service.rb @@ -14,9 +14,10 @@ module Gitlab end def authorized_resolve - proc do |obj, args, ctx| - resolved_obj = @old_resolve_proc.call(obj, args, ctx) - checker = build_checker(ctx[:current_user]) + proc do |parent_typed_object, args, ctx| + resolved_obj = @old_resolve_proc.call(parent_typed_object, args, ctx) + authorizing_obj = authorize_against(parent_typed_object) + checker = build_checker(ctx[:current_user], authorizing_obj) if resolved_obj.respond_to?(:then) resolved_obj.then(&checker) @@ -51,22 +52,28 @@ module Gitlab Array.wrap(@field.metadata[:authorize]) end - def build_checker(current_user) - lambda do |value| + # If it's a built-in/scalar type, authorize using its parent object. + # nil means authorize using the resolved object + def authorize_against(parent_typed_object) + parent_typed_object.object if built_in_type? && parent_typed_object.respond_to?(:object) + end + + def build_checker(current_user, authorizing_obj) + lambda do |resolved_obj| # Load the elements if they were not loaded by BatchLoader yet - value = value.sync if value.respond_to?(:sync) + resolved_obj = resolved_obj.sync if resolved_obj.respond_to?(:sync) check = lambda do |object| authorizations.all? do |ability| - Ability.allowed?(current_user, ability, object) + Ability.allowed?(current_user, ability, authorizing_obj || object) end end - case value + case resolved_obj when Array, ActiveRecord::Relation - value.select(&check) + resolved_obj.select(&check) else - value if check.call(value) + resolved_obj if check.call(resolved_obj) end end end @@ -88,6 +95,10 @@ module Gitlab def node_type_for_basic_connection(type) type.unwrap end + + def built_in_type? + GraphQL::Schema::BUILT_IN_TYPES.has_value?(node_type_for_basic_connection(@field.type)) + end end end end 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 diff --git a/lib/gitlab/url_helpers.rb b/lib/gitlab/url_helpers.rb new file mode 100644 index 00000000000..883585c196f --- /dev/null +++ b/lib/gitlab/url_helpers.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Gitlab + class UrlHelpers + WSS_PROTOCOL = "wss".freeze + def self.as_wss(url) + return unless url.present? + + URI.parse(url).tap do |uri| + uri.scheme = WSS_PROTOCOL + end.to_s + rescue URI::InvalidURIError + nil + end + end +end diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 83eabb8d674..533757d2237 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -162,16 +162,16 @@ module Gitlab ] end - def terminal_websocket(terminal) + def channel_websocket(channel) details = { - 'Terminal' => { - 'Subprotocols' => terminal[:subprotocols], - 'Url' => terminal[:url], - 'Header' => terminal[:headers], - 'MaxSessionTime' => terminal[:max_session_time] + 'Channel' => { + 'Subprotocols' => channel[:subprotocols], + 'Url' => channel[:url], + 'Header' => channel[:headers], + 'MaxSessionTime' => channel[:max_session_time] } } - details['Terminal']['CAPem'] = terminal[:ca_pem] if terminal.key?(:ca_pem) + details['Channel']['CAPem'] = channel[:ca_pem] if channel.key?(:ca_pem) details end |