summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/entities.rb12
-rw-r--r--lib/api/files.rb1
-rw-r--r--lib/api/helpers.rb8
-rw-r--r--lib/api/helpers/headers_helpers.rb8
-rw-r--r--lib/banzai/reference_parser/base_parser.rb8
-rw-r--r--lib/gitlab/asciidoc.rb2
-rw-r--r--lib/gitlab/asciidoc/include_processor.rb13
-rw-r--r--lib/gitlab/git/cross_repo_comparer.rb56
-rw-r--r--lib/gitlab/git/repository.rb33
-rw-r--r--lib/gitlab/no_cache_headers.rb15
-rw-r--r--lib/gitlab/reference_extractor.rb11
13 files changed, 132 insertions, 39 deletions
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index d108c811f4b..e0a6dc41b65 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -85,6 +85,8 @@ module API
protected: @project.protected_for?(ref))
end
+ authorize! :update_pipeline, pipeline
+
status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
project: @project,
pipeline: pipeline,
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 63a7fdfa3ab..9dcf9b015aa 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -154,7 +154,7 @@ module API
not_found! 'Commit' unless commit
- present commit, with: Entities::CommitDetail, stats: params[:stats]
+ present commit, with: Entities::CommitDetail, stats: params[:stats], current_user: current_user
end
desc 'Get the diff for a specific commit of a project' do
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 32a0fb9dd60..694c48f644a 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -456,8 +456,18 @@ module API
class CommitDetail < Commit
expose :stats, using: Entities::CommitStats, if: :stats
expose :status
- expose :last_pipeline, using: 'API::Entities::PipelineBasic'
expose :project_id
+
+ expose :last_pipeline do |commit, options|
+ pipeline = commit.last_pipeline if can_read_pipeline?
+ ::API::Entities::PipelineBasic.represent(pipeline, options)
+ end
+
+ private
+
+ def can_read_pipeline?
+ Ability.allowed?(options[:current_user], :read_pipeline, object.last_pipeline)
+ end
end
class CommitSignature < Grape::Entity
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 0b438fb5bbc..feed22d188c 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -127,6 +127,7 @@ module API
get ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
+ no_cache_headers
set_http_headers(blob_data)
send_git_blob @repo, @blob
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 49b86489a8b..4dcbd26775d 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -256,11 +256,19 @@ module API
end
def require_gitlab_workhorse!
+ verify_workhorse_api!
+
unless env['HTTP_GITLAB_WORKHORSE'].present?
forbidden!('Request should be executed via GitLab Workhorse')
end
end
+ def verify_workhorse_api!
+ Gitlab::Workhorse.verify_api_request!(request.headers)
+ rescue
+ forbidden!
+ end
+
def require_pages_enabled!
not_found! unless user_project.pages_available?
end
diff --git a/lib/api/helpers/headers_helpers.rb b/lib/api/helpers/headers_helpers.rb
index 7553af9d156..908c57bb04e 100644
--- a/lib/api/helpers/headers_helpers.rb
+++ b/lib/api/helpers/headers_helpers.rb
@@ -3,6 +3,8 @@
module API
module Helpers
module HeadersHelpers
+ include Gitlab::NoCacheHeaders
+
def set_http_headers(header_data)
header_data.each do |key, value|
if value.is_a?(Enumerable)
@@ -12,6 +14,12 @@ module API
header "X-Gitlab-#{key.to_s.split('_').collect(&:capitalize).join('-')}", value.to_s
end
end
+
+ def no_cache_headers
+ DEFAULT_GITLAB_NO_CACHE_HEADERS.each do |k, v|
+ header k, v
+ end
+ end
end
end
end
diff --git a/lib/banzai/reference_parser/base_parser.rb b/lib/banzai/reference_parser/base_parser.rb
index 8419769085a..ffc6bdc612d 100644
--- a/lib/banzai/reference_parser/base_parser.rb
+++ b/lib/banzai/reference_parser/base_parser.rb
@@ -201,12 +201,14 @@ module Banzai
gather_references(nodes)
end
- # Gathers the references for the given HTML nodes.
+ # Gathers the references for the given HTML nodes. Returns visible
+ # references and a list of nodes which are not visible to the user
def gather_references(nodes)
nodes = nodes_user_can_reference(current_user, nodes)
- nodes = nodes_visible_to_user(current_user, nodes)
+ visible = nodes_visible_to_user(current_user, nodes)
+ not_visible = nodes - visible
- referenced_by(nodes)
+ { visible: referenced_by(visible), not_visible: not_visible }
end
# Returns a Hash containing the projects for a given list of HTML nodes.
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index da65caa6c9c..8d072422e17 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -11,6 +11,7 @@ module Gitlab
# the resulting HTML through HTML pipeline filters.
module Asciidoc
MAX_INCLUDE_DEPTH = 5
+ MAX_INCLUDES = 32
DEFAULT_ADOC_ATTRS = {
'showtitle' => true,
'sectanchors' => true,
@@ -40,6 +41,7 @@ module Gitlab
extensions: extensions }
context[:pipeline] = :ascii_doc
+ context[:max_includes] = [MAX_INCLUDES, context[:max_includes]].compact.min
plantuml_setup
diff --git a/lib/gitlab/asciidoc/include_processor.rb b/lib/gitlab/asciidoc/include_processor.rb
index c6fbf540e9c..c3dca21b4b5 100644
--- a/lib/gitlab/asciidoc/include_processor.rb
+++ b/lib/gitlab/asciidoc/include_processor.rb
@@ -13,7 +13,9 @@ module Gitlab
super(logger: Gitlab::AppLogger)
@context = context
- @repository = context[:project].try(:repository)
+ @repository = context[:repository] || context[:project].try(:repository)
+ @max_includes = context[:max_includes].to_i
+ @included = []
# Note: Asciidoctor calls #freeze on extensions, so we can't set new
# instance variables after initialization.
@@ -28,8 +30,11 @@ module Gitlab
def include_allowed?(target, reader)
doc = reader.document
- return false if doc.attributes.fetch('max-include-depth').to_i < 1
+ max_include_depth = doc.attributes.fetch('max-include-depth').to_i
+
+ return false if max_include_depth < 1
return false if target_uri?(target)
+ return false if included.size >= max_includes
true
end
@@ -62,7 +67,7 @@ module Gitlab
private
- attr_accessor :context, :repository, :cache
+ attr_reader :context, :repository, :cache, :max_includes, :included
# Gets a Blob at a path for a specific revision.
# This method will check that the Blob exists and contains readable text.
@@ -77,6 +82,8 @@ module Gitlab
raise 'Blob not found' unless blob
raise 'File is not readable' unless blob.readable_text?
+ included << filename
+
blob
end
diff --git a/lib/gitlab/git/cross_repo_comparer.rb b/lib/gitlab/git/cross_repo_comparer.rb
new file mode 100644
index 00000000000..3958373f7cb
--- /dev/null
+++ b/lib/gitlab/git/cross_repo_comparer.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Git
+ class CrossRepoComparer
+ attr_reader :source_repo, :target_repo
+
+ def initialize(source_repo, target_repo)
+ @source_repo = source_repo
+ @target_repo = target_repo
+ end
+
+ def compare(source_ref, target_ref, straight:)
+ ensuring_ref_in_source(target_ref) do |target_commit_id|
+ Gitlab::Git::Compare.new(
+ source_repo,
+ target_commit_id,
+ source_ref,
+ straight: straight
+ )
+ end
+ end
+
+ private
+
+ def ensuring_ref_in_source(ref, &blk)
+ return yield ref if source_repo == target_repo
+
+ # If the commit doesn't exist in the target, there's nothing we can do
+ commit_id = target_repo.commit(ref)&.sha
+ return unless commit_id
+
+ # The commit pointed to by ref may exist in the source even when they
+ # are different repositories. This is particularly true of close forks,
+ # but may also be the case if a temporary ref for this comparison has
+ # already been created in the past, and the result hasn't been GC'd yet.
+ return yield commit_id if source_repo.commit(commit_id)
+
+ # Worst case: the commit is not in the source repo so we need to fetch
+ # it. Use a temporary ref and clean up afterwards
+ with_commit_in_source_tmp(commit_id, &blk)
+ end
+
+ # Fetch the ref into source_repo from target_repo, using a temporary ref
+ # name that will be deleted once the method completes. This is a no-op if
+ # fetching the source branch fails
+ def with_commit_in_source_tmp(commit_id, &blk)
+ tmp_ref = "refs/tmp/#{SecureRandom.hex}"
+
+ yield commit_id if source_repo.fetch_source_branch!(target_repo, commit_id, tmp_ref)
+ ensure
+ source_repo.delete_refs(tmp_ref) # best-effort
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 4971a18e270..ea44a2f40c0 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -746,29 +746,9 @@ module Gitlab
end
def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:)
- reachable_ref =
- if source_repository == self
- source_branch_name
- else
- # If a tmp ref was created before for a separate repo comparison (forks),
- # we're able to short-circuit the tmp ref re-creation:
- # 1. Take the SHA from the source repo
- # 2. Read that in the current "target" repo
- # 3. If that SHA is still known (readable), it means GC hasn't
- # cleaned it up yet, so we can use it instead re-writing the tmp ref.
- source_commit_id = source_repository.commit(source_branch_name)&.sha
- commit(source_commit_id)&.sha if source_commit_id
- end
-
- return compare(target_branch_name, reachable_ref, straight: straight) if reachable_ref
-
- tmp_ref = "refs/tmp/#{SecureRandom.hex}"
-
- return unless fetch_source_branch!(source_repository, source_branch_name, tmp_ref)
-
- compare(target_branch_name, tmp_ref, straight: straight)
- ensure
- delete_refs(tmp_ref) if tmp_ref
+ CrossRepoComparer
+ .new(source_repository, self)
+ .compare(source_branch_name, target_branch_name, straight: straight)
end
def write_ref(ref_path, ref, old_ref: nil)
@@ -1045,13 +1025,6 @@ module Gitlab
private
- def compare(base_ref, head_ref, straight:)
- Gitlab::Git::Compare.new(self,
- base_ref,
- head_ref,
- straight: straight)
- end
-
def empty_diff_stats
Gitlab::Git::DiffStatsCollection.new([])
end
diff --git a/lib/gitlab/no_cache_headers.rb b/lib/gitlab/no_cache_headers.rb
new file mode 100644
index 00000000000..f80ca2c1369
--- /dev/null
+++ b/lib/gitlab/no_cache_headers.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module NoCacheHeaders
+ DEFAULT_GITLAB_NO_CACHE_HEADERS = {
+ 'Cache-Control' => "#{ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL}, no-store, no-cache",
+ 'Pragma' => 'no-cache', # HTTP 1.0 compatibility
+ 'Expires' => 'Fri, 01 Jan 1990 00:00:00 GMT'
+ }.freeze
+
+ def no_cache_headers
+ raise "#no_cache_headers is not implemented for this object"
+ end
+ end
+end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index ea2b03b42c1..48276465efd 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -6,11 +6,16 @@ module Gitlab
REFERABLES = %i(user issue label milestone
merge_request snippet commit commit_range directly_addressed_user epic).freeze
attr_accessor :project, :current_user, :author
+ # This counter is increased by a number of references filtered out by
+ # banzai reference exctractor. Note that this counter is stateful and
+ # not idempotent and is increased whenever you call `references`.
+ attr_reader :stateful_not_visible_counter
def initialize(project, current_user = nil)
@project = project
@current_user = current_user
@references = {}
+ @stateful_not_visible_counter = 0
super()
end
@@ -20,11 +25,15 @@ module Gitlab
end
def references(type)
- super(type, project, current_user)
+ refs = super(type, project, current_user)
+ @stateful_not_visible_counter += refs[:not_visible].count
+
+ refs[:visible]
end
def reset_memoized_values
@references = {}
+ @stateful_not_visible_counter = 0
super()
end