summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/branches.rb16
-rw-r--r--lib/api/helpers.rb8
-rw-r--r--lib/api/internal.rb9
-rw-r--r--lib/api/issues.rb61
-rw-r--r--lib/api/labels.rb4
-rw-r--r--lib/api/merge_requests.rb11
-rw-r--r--lib/api/repositories.rb17
-rw-r--r--lib/backup/repository.rb2
-rw-r--r--lib/gitlab/backend/shell.rb9
-rw-r--r--lib/gitlab/blacklist.rb27
-rw-r--r--lib/gitlab/diff/file.rb49
-rw-r--r--lib/gitlab/diff/line.rb12
-rw-r--r--lib/gitlab/diff/line_code.rb9
-rw-r--r--lib/gitlab/diff/parser.rb81
-rw-r--r--lib/gitlab/diff_parser.rb83
-rw-r--r--lib/gitlab/git_access.rb39
-rw-r--r--lib/gitlab/git_ref_validator.rb11
-rw-r--r--lib/gitlab/ldap/access.rb2
-rw-r--r--lib/gitlab/ldap/adapter.rb3
-rw-r--r--lib/gitlab/ldap/person.rb2
-rw-r--r--lib/gitlab/ldap/user.rb91
-rw-r--r--lib/gitlab/markdown.rb16
-rw-r--r--lib/gitlab/oauth/auth_hash.rb54
-rw-r--r--lib/gitlab/oauth/user.rb134
-rw-r--r--lib/gitlab/project_search_results.rb73
-rw-r--r--lib/gitlab/satellite/satellite.rb1
-rw-r--r--lib/gitlab/search_results.rb69
-rw-r--r--lib/gitlab/snippet_search_results.rb131
-rw-r--r--lib/gitlab/upgrader.rb2
-rw-r--r--lib/gitlab/visibility_level.rb16
-rw-r--r--lib/support/nginx/gitlab96
-rw-r--r--lib/support/nginx/gitlab-ssl57
-rw-r--r--lib/tasks/gitlab/check.rake12
-rw-r--r--lib/tasks/gitlab/shell.rake2
-rw-r--r--lib/tasks/gitlab/sidekiq.rake47
35 files changed, 907 insertions, 349 deletions
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index b32a4aa7bc2..4db5f61dd28 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -80,9 +80,17 @@ module API
# POST /projects/:id/repository/branches
post ":id/repository/branches" do
authorize_push_project
- @branch = CreateBranchService.new.execute(user_project, params[:branch_name], params[:ref], current_user)
-
- present @branch, with: Entities::RepoObject, project: user_project
+ result = CreateBranchService.new.execute(user_project,
+ params[:branch_name],
+ params[:ref],
+ current_user)
+ if result[:status] == :success
+ present result[:branch],
+ with: Entities::RepoObject,
+ project: user_project
+ else
+ render_api_error!(result[:message], 400)
+ end
end
# Delete branch
@@ -99,7 +107,7 @@ module API
if result[:state] == :success
true
else
- render_api_error!(result[:message], 405)
+ render_api_error!(result[:message], result[:return_code])
end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index d36b29a00b1..6af0f6d1b25 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -114,17 +114,21 @@ module API
# Helper method for validating all labels against its names
def validate_label_params(params)
+ errors = {}
+
if params[:labels].present?
params[:labels].split(',').each do |label_name|
label = user_project.labels.create_with(
color: Label::DEFAULT_COLOR).find_or_initialize_by(
title: label_name.strip)
+
if label.invalid?
- return true
+ errors[label.title] = label.errors
end
end
end
- false
+
+ errors
end
# error helpers
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 5850892df07..5f484f63418 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -12,7 +12,9 @@ module API
# ref - branch name
# forced_push - forced_push
#
- get "/allowed" do
+ post "/allowed" do
+ status 200
+
# Check for *.wiki repositories.
# Strip out the .wiki from the pathname before finding the
# project. This applies the correct project permissions to
@@ -34,10 +36,7 @@ module API
actor,
params[:action],
project,
- params[:ref],
- params[:oldrev],
- params[:newrev],
- params[:forced_push]
+ params[:changes]
)
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 055529ccbd8..5369149cdfc 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -3,13 +3,41 @@ module API
class Issues < Grape::API
before { authenticate! }
+ helpers do
+ def filter_issues_state(issues, state = nil)
+ case state
+ when 'opened' then issues.opened
+ when 'closed' then issues.closed
+ else issues
+ end
+ end
+
+ def filter_issues_labels(issues, labels)
+ issues.includes(:labels).where("labels.title" => labels.split(','))
+ end
+ end
+
resource :issues do
# Get currently authenticated user's issues
#
- # Example Request:
+ # Parameters:
+ # state (optional) - Return "opened" or "closed" issues
+ # labels (optional) - Comma-separated list of label names
+
+ # Example Requests:
# GET /issues
+ # GET /issues?state=opened
+ # GET /issues?state=closed
+ # GET /issues?labels=foo
+ # GET /issues?labels=foo,bar
+ # GET /issues?labels=foo,bar&state=opened
get do
- present paginate(current_user.issues), with: Entities::Issue
+ issues = current_user.issues
+ issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
+ issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
+ issues = issues.order('issues.id DESC')
+
+ present paginate(issues), with: Entities::Issue
end
end
@@ -18,10 +46,24 @@ module API
#
# Parameters:
# id (required) - The ID of a project
- # Example Request:
+ # state (optional) - Return "opened" or "closed" issues
+ # labels (optional) - Comma-separated list of label names
+ #
+ # Example Requests:
# GET /projects/:id/issues
+ # GET /projects/:id/issues?state=opened
+ # GET /projects/:id/issues?state=closed
+ # GET /projects/:id/issues
+ # GET /projects/:id/issues?labels=foo
+ # GET /projects/:id/issues?labels=foo,bar
+ # GET /projects/:id/issues?labels=foo,bar&state=opened
get ":id/issues" do
- present paginate(user_project.issues), with: Entities::Issue
+ issues = user_project.issues
+ issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
+ issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
+ issues = issues.order('issues.id DESC')
+
+ present paginate(issues), with: Entities::Issue
end
# Get a single project issue
@@ -52,8 +94,8 @@ module API
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
issue = ::Issues::CreateService.new(user_project, current_user, attrs).execute
@@ -90,8 +132,8 @@ module API
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
issue = ::Issues::UpdateService.new(user_project, current_user, attrs).execute(issue)
@@ -99,7 +141,8 @@ module API
if issue.valid?
# Find or create labels and attach to issue. Labels are valid because
# we already checked its name, so there can't be an error here
- if params[:labels].present?
+ unless params[:labels].nil?
+ issue.remove_labels
# Create and add labels to the new created issue
issue.add_labels_by_names(params[:labels].split(','))
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index d1684b2293c..2fdf53ffec2 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -39,7 +39,7 @@ module API
if label.valid?
present label, with: Entities::Label
else
- render_api_error!(label.errors.full_messages.join(', '), 405)
+ render_api_error!(label.errors.full_messages.join(', '), 400)
end
end
@@ -95,7 +95,7 @@ module API
if label.update(attrs)
present label, with: Entities::Label
else
- render_api_error!(label.errors.full_messages.join(', '), 405)
+ render_api_error!(label.errors.full_messages.join(', '), 400)
end
end
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 0d765f9280e..8726379bf3c 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -78,8 +78,8 @@ module API
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute
@@ -117,15 +117,16 @@ module API
authorize! :modify_merge_request, merge_request
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request)
if merge_request.valid?
# Find or create labels and attach to issue
- if params[:labels].present?
+ unless params[:labels].nil?
+ merge_request.remove_labels
merge_request.add_labels_by_names(params[:labels].split(","))
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 42068bb343d..07c29aa7b4c 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -32,14 +32,23 @@ module API
# id (required) - The ID of a project
# tag_name (required) - The name of the tag
# ref (required) - Create tag from commit sha or branch
+ # message (optional) - Specifying a message creates an annotated tag.
# Example Request:
# POST /projects/:id/repository/tags
post ':id/repository/tags' do
authorize_push_project
- @tag = CreateTagService.new.execute(user_project, params[:tag_name],
- params[:ref], current_user)
-
- present @tag, with: Entities::RepoObject, project: user_project
+ message = params[:message] || nil
+ result = CreateTagService.new.execute(user_project, params[:tag_name],
+ params[:ref], message,
+ current_user)
+
+ if result[:status] == :success
+ present result[:tag],
+ with: Entities::RepoObject,
+ project: user_project
+ else
+ render_api_error!(result[:message], 400)
+ end
end
# Get a project repository tree
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 6f7c4f7c909..ea05fa2c261 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -69,7 +69,7 @@ module Backup
end
print 'Put GitLab hooks in repositories dirs'.yellow
- if system("#{Gitlab.config.gitlab_shell.path}/support/rewrite-hooks.sh", Gitlab.config.gitlab_shell.repos_path)
+ if system("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks")
puts " [DONE]".green
else
puts " [FAILED]".red
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 53bff3037e5..907373ab991 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -107,12 +107,17 @@ module Gitlab
# path - project path with namespace
# tag_name - new tag name
# ref - HEAD for new tag
+ # message - optional message for tag (annotated tag)
#
# Ex.
# add_tag("gitlab/gitlab-ci", "v4.0", "master")
+ # add_tag("gitlab/gitlab-ci", "v4.0", "master", "message")
#
- def add_tag(path, tag_name, ref)
- system "#{gitlab_shell_path}/bin/gitlab-projects", "create-tag", "#{path}.git", tag_name, ref
+ def add_tag(path, tag_name, ref, message = nil)
+ cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git
+ #{tag_name} #{ref})
+ cmd << message unless message.nil? || message.empty?
+ system *cmd
end
# Remove repository tag
diff --git a/lib/gitlab/blacklist.rb b/lib/gitlab/blacklist.rb
index 6bc2c3b487c..43145e0ee1b 100644
--- a/lib/gitlab/blacklist.rb
+++ b/lib/gitlab/blacklist.rb
@@ -3,7 +3,32 @@ module Gitlab
extend self
def path
- %w(admin dashboard files groups help profile projects search public assets u s teams merge_requests issues users snippets services repository hooks notes)
+ %w(
+ admin
+ dashboard
+ files
+ groups
+ help
+ profile
+ projects
+ search
+ public
+ assets
+ u
+ s
+ teams
+ merge_requests
+ issues
+ users
+ snippets
+ services
+ repository
+ hooks
+ notes
+ unsubscribes
+ all
+ ci
+ )
end
end
end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
new file mode 100644
index 00000000000..19a1198c68c
--- /dev/null
+++ b/lib/gitlab/diff/file.rb
@@ -0,0 +1,49 @@
+module Gitlab
+ module Diff
+ class File
+ attr_reader :diff
+
+ delegate :new_file, :deleted_file, :renamed_file,
+ :old_path, :new_path, to: :diff, prefix: false
+
+ def initialize(diff)
+ @diff = diff
+ end
+
+ # Array of Gitlab::DIff::Line objects
+ def diff_lines
+ @lines ||= parser.parse(raw_diff.lines)
+ end
+
+ def mode_changed?
+ !!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode)
+ end
+
+ def parser
+ Gitlab::Diff::Parser.new
+ end
+
+ def raw_diff
+ diff.diff
+ end
+
+ def next_line(index)
+ diff_lines[index + 1]
+ end
+
+ def prev_line(index)
+ if index > 0
+ diff_lines[index - 1]
+ end
+ end
+
+ def file_path
+ if diff.new_path.present?
+ diff.new_path
+ elsif diff.old_path.present?
+ diff.old_path
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
new file mode 100644
index 00000000000..8ac1b15e88a
--- /dev/null
+++ b/lib/gitlab/diff/line.rb
@@ -0,0 +1,12 @@
+module Gitlab
+ module Diff
+ class Line
+ attr_reader :type, :text, :index, :old_pos, :new_pos
+
+ def initialize(text, type, index, old_pos, new_pos)
+ @text, @type, @index = text, type, index
+ @old_pos, @new_pos = old_pos, new_pos
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line_code.rb b/lib/gitlab/diff/line_code.rb
new file mode 100644
index 00000000000..f3578ab3d35
--- /dev/null
+++ b/lib/gitlab/diff/line_code.rb
@@ -0,0 +1,9 @@
+module Gitlab
+ module Diff
+ class LineCode
+ def self.generate(file_path, new_line_position, old_line_position)
+ "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
new file mode 100644
index 00000000000..9d6309954a4
--- /dev/null
+++ b/lib/gitlab/diff/parser.rb
@@ -0,0 +1,81 @@
+module Gitlab
+ module Diff
+ class Parser
+ include Enumerable
+
+ def parse(lines)
+ @lines = lines,
+ lines_obj = []
+ line_obj_index = 0
+ line_old = 1
+ line_new = 1
+ type = nil
+
+ lines_arr = ::Gitlab::InlineDiff.processing lines
+
+ lines_arr.each do |line|
+ raw_line = line.dup
+
+ next if filename?(line)
+
+ full_line = html_escape(line.gsub(/\n/, ''))
+ full_line = ::Gitlab::InlineDiff.replace_markers full_line
+
+ if line.match(/^@@ -/)
+ type = "match"
+
+ line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
+ line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
+
+ next if line_old == 1 && line_new == 1 #top of file
+ lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ next
+ else
+ type = identification_type(line)
+ lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ end
+
+
+ if line[0] == "+"
+ line_new += 1
+ elsif line[0] == "-"
+ line_old += 1
+ else
+ line_new += 1
+ line_old += 1
+ end
+ end
+
+ lines_obj
+ end
+
+ def empty?
+ @lines.empty?
+ end
+
+ private
+
+ def filename?(line)
+ line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
+ '--- /tmp/diffy', '+++ /tmp/diffy')
+ end
+
+ def identification_type(line)
+ if line[0] == "+"
+ "new"
+ elsif line[0] == "-"
+ "old"
+ else
+ nil
+ end
+ end
+
+ def html_escape str
+ replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
+ str.gsub(/[&"'><]/, replacements)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff_parser.rb b/lib/gitlab/diff_parser.rb
deleted file mode 100644
index b244295027e..00000000000
--- a/lib/gitlab/diff_parser.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-module Gitlab
- class DiffParser
- include Enumerable
-
- attr_reader :lines, :new_path
-
- def initialize(lines, new_path = '')
- @lines = lines
- @new_path = new_path
- end
-
- def each
- line_old = 1
- line_new = 1
- type = nil
-
- lines_arr = ::Gitlab::InlineDiff.processing lines
- lines_arr.each do |line|
- raw_line = line.dup
-
- next if filename?(line)
-
- full_line = html_escape(line.gsub(/\n/, ''))
- full_line = ::Gitlab::InlineDiff.replace_markers full_line
-
- if line.match(/^@@ -/)
- type = "match"
-
- line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
- line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
-
- next if line_old == 1 && line_new == 1 #top of file
- yield(full_line, type, nil, line_new, line_old)
- next
- else
- type = identification_type(line)
- line_code = generate_line_code(new_path, line_new, line_old)
- yield(full_line, type, line_code, line_new, line_old, raw_line)
- end
-
-
- if line[0] == "+"
- line_new += 1
- elsif line[0] == "-"
- line_old += 1
- else
- line_new += 1
- line_old += 1
- end
- end
- end
-
- def empty?
- @lines.empty?
- end
-
- private
-
- def filename?(line)
- line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
- '--- /tmp/diffy', '+++ /tmp/diffy')
- end
-
- def identification_type(line)
- if line[0] == "+"
- "new"
- elsif line[0] == "-"
- "old"
- else
- nil
- end
- end
-
- def generate_line_code(path, line_new, line_old)
- "#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
- end
-
- def html_escape str
- replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
- str.gsub(/[&"'><]/, replacements)
- end
- end
-end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 38b3d82e2f4..e75a5a1d62e 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -5,7 +5,7 @@ module Gitlab
attr_reader :params, :project, :git_cmd, :user
- def allowed?(actor, cmd, project, ref = nil, oldrev = nil, newrev = nil, forced_push = false)
+ def allowed?(actor, cmd, project, changes = nil)
case cmd
when *DOWNLOAD_COMMANDS
if actor.is_a? User
@@ -19,12 +19,12 @@ module Gitlab
end
when *PUSH_COMMANDS
if actor.is_a? User
- push_allowed?(actor, project, ref, oldrev, newrev, forced_push)
+ push_allowed?(actor, project, changes)
elsif actor.is_a? DeployKey
# Deploy key not allowed to push
return false
elsif actor.is_a? Key
- push_allowed?(actor.user, project, ref, oldrev, newrev, forced_push)
+ push_allowed?(actor.user, project, changes)
else
raise 'Wrong actor'
end
@@ -41,13 +41,21 @@ module Gitlab
end
end
- def push_allowed?(user, project, ref, oldrev, newrev, forced_push)
- if user && user_allowed?(user)
+ def push_allowed?(user, project, changes)
+ return false unless user && user_allowed?(user)
+ return true if changes.blank?
+
+ changes = changes.lines if changes.kind_of?(String)
+
+ # Iterate over all changes to find if user allowed all of them to be applied
+ changes.each do |change|
+ oldrev, newrev, ref = changes.split('')
+
action = if project.protected_branch?(ref)
# we dont allow force push to protected branch
- if forced_push.to_s == 'true'
+ if forced_push?(oldrev, newrev)
:force_push_code_to_protected_branches
- # and we dont allow remove of protected branch
+ # and we dont allow remove of protected branch
elsif newrev =~ /0000000/
:remove_protected_branches
else
@@ -59,7 +67,22 @@ module Gitlab
else
:push_code
end
- user.can?(action, project)
+ unless user.can?(action, project)
+ # If user does not have access to make at least one change - cancel all push
+ return false
+ end
+ end
+
+ # If user has access to make all changes
+ true
+ end
+
+ def forced_push?(oldrev, newrev)
+ return false if project.empty_repo?
+
+ if oldrev !~ /00000000/ && newrev !~ /00000000/
+ missed_refs = IO.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})).read
+ missed_refs.split("\n").size > 0
else
false
end
diff --git a/lib/gitlab/git_ref_validator.rb b/lib/gitlab/git_ref_validator.rb
new file mode 100644
index 00000000000..13cb08948bb
--- /dev/null
+++ b/lib/gitlab/git_ref_validator.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ module GitRefValidator
+ extend self
+ # Validates a given name against the git reference specification
+ #
+ # Returns true for a valid reference name, false otherwise
+ def validate(ref_name)
+ system *%W(git check-ref-format refs/#{ref_name})
+ end
+ end
+end
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index 62709a12942..c054b6f5865 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -28,7 +28,7 @@ module Gitlab
def allowed?(user)
if Gitlab::LDAP::Person.find_by_dn(user.extern_uid, adapter)
- !Gitlab::LDAP::Person.active_directory_disabled?(user.extern_uid, adapter)
+ !Gitlab::LDAP::Person.disabled_via_active_directory?(user.extern_uid, adapter)
else
false
end
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index ca239bea884..68ac1b22909 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -86,7 +86,8 @@ module Gitlab
end
def dn_matches_filter?(dn, filter)
- ldap_search(base: dn, filter: filter, scope: Net::LDAP::SearchScope_BaseObject, attributes: %w{dn}).any?
+ ldap_search(base: dn, filter: filter,
+ scope: Net::LDAP::SearchScope_BaseObject, attributes: %w{dn}).any?
end
def ldap_search(*args)
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 9ad6618bd46..87c3d711db4 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -16,7 +16,7 @@ module Gitlab
adapter.user('dn', dn)
end
- def self.active_directory_disabled?(dn, adapter=nil)
+ def self.disabled_via_active_directory?(dn, adapter=nil)
adapter ||= Gitlab::LDAP::Adapter.new
adapter.dn_matches_filter?(dn, AD_USER_DISABLED)
end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index be3fcc4f035..25b5a702f9a 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -10,52 +10,20 @@ module Gitlab
module LDAP
class User < Gitlab::OAuth::User
class << self
- def find_or_create(auth)
- @auth = auth
-
- if uid.blank? || email.blank? || username.blank?
- raise_error("Account must provide a dn, uid and email address")
- end
-
- user = find(auth)
-
- unless user
- # Look for user with same emails
- #
- # Possible cases:
- # * When user already has account and need to link their LDAP account.
- # * LDAP uid changed for user with same email and we need to update their uid
- #
- user = find_user(email)
-
- if user
- user.update_attributes(extern_uid: uid, provider: provider)
- log.info("(LDAP) Updating legacy LDAP user #{email} with extern_uid => #{uid}")
- else
- # Create a new user inside GitLab database
- # based on LDAP credentials
- #
- #
- user = create(auth)
- end
- end
-
- user
+ def find_or_create(auth_hash)
+ self.auth_hash = auth_hash
+ find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash)
end
- def find_user(email)
- user = model.find_by(email: email)
+ def find_and_connect_by_email(auth_hash)
+ self.auth_hash = auth_hash
+ user = model.find_by(email: self.auth_hash.email)
- # If no user found and allow_username_or_email_login is true
- # we look for user by extracting part of their email
- if !user && email && ldap_conf['allow_username_or_email_login']
- uname = email.partition('@').first
- # Strip apostrophes since they are disallowed as part of username
- username = uname.gsub("'", "")
- user = model.find_by(username: username)
+ if user
+ user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider)
+ Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}")
+ return user
end
-
- user
end
def authenticate(login, password)
@@ -63,17 +31,8 @@ module Gitlab
# Only check with valid login and password to prevent anonymous bind results
return nil unless ldap_conf.enabled && login.present? && password.present?
- ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
- filter = Net::LDAP::Filter.eq(ldap.uid, login)
-
- # Apply LDAP user filter if present
- if ldap_conf['user_filter'].present?
- user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
- filter = Net::LDAP::Filter.join(filter, user_filter)
- end
-
- ldap_user = ldap.bind_as(
- filter: filter,
+ ldap_user = adapter.bind_as(
+ filter: user_filter(login),
size: 1,
password: password
)
@@ -81,10 +40,14 @@ module Gitlab
find_by_uid(ldap_user.dn) if ldap_user
end
- private
+ def adapter
+ @adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf)
+ end
+
+ protected
def find_by_uid_and_provider
- find_by_uid(uid)
+ find_by_uid(auth_hash.uid)
end
def find_by_uid(uid)
@@ -92,10 +55,6 @@ module Gitlab
model.where("provider = ? and lower(extern_uid) = ?", provider, uid.downcase).last
end
- def username
- auth.info.nickname.to_s.force_encoding("utf-8")
- end
-
def provider
'ldap'
end
@@ -107,6 +66,20 @@ module Gitlab
def ldap_conf
Gitlab.config.ldap
end
+
+ def user_filter(login)
+ filter = Net::LDAP::Filter.eq(adapter.uid, login)
+ # Apply LDAP user filter if present
+ if ldap_conf['user_filter'].present?
+ user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
+ filter = Net::LDAP::Filter.join(filter, user_filter)
+ end
+ filter
+ end
+ end
+
+ def needs_blocking?
+ false
end
end
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index b248d8f9436..6017a4c86c1 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -192,8 +192,12 @@ module Gitlab
link_to("##{identifier}", url, options)
end
- elsif project.issues_tracker == 'jira'
- reference_jira_issue(identifier, project)
+ else
+ config = Gitlab.config
+ external_issue_tracker = config.issues_tracker[project.issues_tracker]
+ if external_issue_tracker.present?
+ reference_external_issue(identifier, external_issue_tracker, project)
+ end
end
end
@@ -229,15 +233,15 @@ module Gitlab
end
end
- def reference_jira_issue(identifier, project = @project)
- url = url_for_issue(identifier)
- title = Gitlab.config.issues_tracker[project.issues_tracker]["title"]
+ def reference_external_issue(identifier, issue_tracker, project = @project)
+ url = url_for_issue(identifier, project)
+ title = issue_tracker['title']
options = html_options.merge(
title: "Issue in #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
- link_to("#{identifier}", url, options)
+ link_to("##{identifier}", url, options)
end
end
end
diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb
new file mode 100644
index 00000000000..0198f61f427
--- /dev/null
+++ b/lib/gitlab/oauth/auth_hash.rb
@@ -0,0 +1,54 @@
+# Class to parse and transform the info provided by omniauth
+#
+module Gitlab
+ module OAuth
+ class AuthHash
+ attr_reader :auth_hash
+ def initialize(auth_hash)
+ @auth_hash = auth_hash
+ end
+
+ def uid
+ auth_hash.uid.to_s
+ end
+
+ def provider
+ auth_hash.provider
+ end
+
+ def info
+ auth_hash.info
+ end
+
+ def name
+ (info.name || full_name).to_s.force_encoding('utf-8')
+ end
+
+ def full_name
+ "#{info.first_name} #{info.last_name}"
+ end
+
+ def username
+ (info.try(:nickname) || generate_username).to_s.force_encoding('utf-8')
+ end
+
+ def email
+ (info.try(:email) || generate_temporarily_email).downcase
+ end
+
+ def password
+ @password ||= Devise.friendly_token[0, 8].downcase
+ end
+
+ # Get the first part of the email address (before @)
+ # In addtion in removes illegal characters
+ def generate_username
+ email.match(/^[^@]*/)[0].parameterize
+ end
+
+ def generate_temporarily_email
+ "temp-email-for-oauth-#{username}@gitlab.localhost"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index 0056eb3a28b..b768eda185f 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -7,106 +7,78 @@ module Gitlab
module OAuth
class User
class << self
- attr_reader :auth
+ attr_reader :auth_hash
- def find(auth)
- @auth = auth
+ def find(auth_hash)
+ self.auth_hash = auth_hash
find_by_uid_and_provider
end
- def create(auth)
- @auth = auth
- password = Devise.friendly_token[0, 8].downcase
- opts = {
- extern_uid: uid,
- provider: provider,
- name: name,
- username: username,
- email: email,
- password: password,
- password_confirmation: password,
- }
-
- user = model.build_user(opts)
- user.skip_confirmation!
-
- # Services like twitter and github does not return email via oauth
- # In this case we generate temporary email and force user to fill it later
- if user.email.blank?
- user.generate_tmp_oauth_email
- elsif provider != "ldap"
- # Google oauth returns email but dont return nickname
- # So we use part of email as username for new user
- # For LDAP, username is already set to the user's
- # uid/userid/sAMAccountName.
- email_username = email.match(/^[^@]*/)[0]
- # Strip apostrophes since they are disallowed as part of username
- user.username = email_username.gsub("'", "")
- end
-
- begin
- user.save!
- rescue ActiveRecord::RecordInvalid => e
- log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
- return nil, e.record.errors
- end
-
- log.info "(OAuth) Creating user #{email} from login with extern_uid => #{uid}"
-
- if Gitlab.config.omniauth['block_auto_created_users'] && !ldap?
- user.block
- end
+ def create(auth_hash)
+ user = new(auth_hash)
+ user.save_and_trigger_callbacks
+ end
- user
+ def model
+ ::User
end
- private
+ def auth_hash=(auth_hash)
+ @auth_hash = AuthHash.new(auth_hash)
+ end
+ protected
def find_by_uid_and_provider
- model.where(provider: provider, extern_uid: uid).last
+ model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
end
+ end
- def uid
- uid = auth.info.uid || auth.uid
- uid = uid.to_s unless uid.nil?
- uid
- end
+ # Instance methods
+ attr_accessor :auth_hash, :user
- def email
- auth.info.email.downcase unless auth.info.email.nil?
- end
+ def initialize(auth_hash)
+ self.auth_hash = auth_hash
+ self.user = self.class.model.new(user_attributes)
+ user.skip_confirmation!
+ end
- def name
- if auth.info.name.nil?
- "#{auth.info.first_name} #{auth.info.last_name}".force_encoding('utf-8')
- else
- auth.info.name.to_s.force_encoding('utf-8')
- end
- end
+ def auth_hash=(auth_hash)
+ @auth_hash = AuthHash.new(auth_hash)
+ end
- def username
- auth.info.nickname.to_s.force_encoding("utf-8")
- end
+ def save_and_trigger_callbacks
+ user.save!
+ log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
+ user.block if needs_blocking?
- def provider
- auth.provider
- end
+ user
+ rescue ActiveRecord::RecordInvalid => e
+ log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
+ return nil, e.record.errors
+ end
- def log
- Gitlab::AppLogger
- end
+ def user_attributes
+ {
+ extern_uid: auth_hash.uid,
+ provider: auth_hash.provider,
+ name: auth_hash.name,
+ username: auth_hash.username,
+ email: auth_hash.email,
+ password: auth_hash.password,
+ password_confirmation: auth_hash.password,
+ }
+ end
- def model
- ::User
- end
+ def log
+ Gitlab::AppLogger
+ end
- def raise_error(message)
- raise OmniAuth::Error, "(OAuth) " + message
- end
+ def raise_error(message)
+ raise OmniAuth::Error, "(OAuth) " + message
+ end
- def ldap?
- provider == 'ldap'
- end
+ def needs_blocking?
+ Gitlab.config.omniauth['block_auto_created_users']
end
end
end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
new file mode 100644
index 00000000000..9dc8b34d9c7
--- /dev/null
+++ b/lib/gitlab/project_search_results.rb
@@ -0,0 +1,73 @@
+module Gitlab
+ class ProjectSearchResults < SearchResults
+ attr_reader :project, :repository_ref
+
+ def initialize(project_id, query, repository_ref = nil)
+ @project = Project.find(project_id)
+ @repository_ref = repository_ref
+ @query = Shellwords.shellescape(query) if query.present?
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'notes'
+ notes.page(page).per(per_page)
+ when 'blobs'
+ Kaminari.paginate_array(blobs).page(page).per(per_page)
+ when 'wiki_blobs'
+ Kaminari.paginate_array(wiki_blobs).page(page).per(per_page)
+ else
+ super
+ end
+ end
+
+ def total_count
+ @total_count ||= issues_count + merge_requests_count + blobs_count +
+ notes_count + wiki_blobs_count
+ end
+
+ def blobs_count
+ @blobs_count ||= blobs.count
+ end
+
+ def notes_count
+ @notes_count ||= notes.count
+ end
+
+ def wiki_blobs_count
+ @wiki_blobs_count ||= wiki_blobs.count
+ end
+
+ private
+
+ def blobs
+ if project.empty_repo?
+ []
+ else
+ project.repository.search_files(query, repository_ref)
+ end
+ end
+
+ def wiki_blobs
+ if project.wiki_enabled?
+ wiki_repo = Repository.new(ProjectWiki.new(project).path_with_namespace)
+
+ if wiki_repo.exists?
+ wiki_repo.search_files(query)
+ else
+ []
+ end
+ else
+ []
+ end
+ end
+
+ def notes
+ Note.where(project_id: limit_project_ids).search(query).order('updated_at DESC')
+ end
+
+ def limit_project_ids
+ [project.id]
+ end
+ end
+end
diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb
index 7c058b58c4c..f34d661c9fc 100644
--- a/lib/gitlab/satellite/satellite.rb
+++ b/lib/gitlab/satellite/satellite.rb
@@ -121,6 +121,7 @@ module Gitlab
#
# Note: this will only update remote branches (i.e. origin/*)
def update_from_source!
+ repo.git.remote(default_options, 'set-url', :origin, project.repository.path_to_repo)
repo.git.fetch(default_options, :origin)
end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
new file mode 100644
index 00000000000..75a3dfe37c3
--- /dev/null
+++ b/lib/gitlab/search_results.rb
@@ -0,0 +1,69 @@
+module Gitlab
+ class SearchResults
+ attr_reader :query
+
+ # Limit search results by passed project ids
+ # It allows us to search only for projects user has access to
+ attr_reader :limit_project_ids
+
+ def initialize(limit_project_ids, query)
+ @limit_project_ids = limit_project_ids || Project.all
+ @query = Shellwords.shellescape(query) if query.present?
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'projects'
+ projects.page(page).per(per_page)
+ when 'issues'
+ issues.page(page).per(per_page)
+ when 'merge_requests'
+ merge_requests.page(page).per(per_page)
+ else
+ Kaminari.paginate_array([]).page(page).per(per_page)
+ end
+ end
+
+ def total_count
+ @total_count ||= projects_count + issues_count + merge_requests_count
+ end
+
+ def projects_count
+ @projects_count ||= projects.count
+ end
+
+ def issues_count
+ @issues_count ||= issues.count
+ end
+
+ def merge_requests_count
+ @merge_requests_count ||= merge_requests.count
+ end
+
+ def empty?
+ total_count.zero?
+ end
+
+ private
+
+ def projects
+ Project.where(id: limit_project_ids).search(query)
+ end
+
+ def issues
+ Issue.where(project_id: limit_project_ids).full_search(query).order('updated_at DESC')
+ end
+
+ def merge_requests
+ MergeRequest.in_projects(limit_project_ids).full_search(query).order('updated_at DESC')
+ end
+
+ def default_scope
+ 'projects'
+ end
+
+ def per_page
+ 20
+ end
+ end
+end
diff --git a/lib/gitlab/snippet_search_results.rb b/lib/gitlab/snippet_search_results.rb
new file mode 100644
index 00000000000..938219efdb2
--- /dev/null
+++ b/lib/gitlab/snippet_search_results.rb
@@ -0,0 +1,131 @@
+module Gitlab
+ class SnippetSearchResults < SearchResults
+ attr_reader :limit_snippet_ids
+
+ def initialize(limit_snippet_ids, query)
+ @limit_snippet_ids = limit_snippet_ids
+ @query = query
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'snippet_titles'
+ Kaminari.paginate_array(snippet_titles).page(page).per(per_page)
+ when 'snippet_blobs'
+ Kaminari.paginate_array(snippet_blobs).page(page).per(per_page)
+ else
+ super
+ end
+ end
+
+ def total_count
+ @total_count ||= snippet_titles_count + snippet_blobs_count
+ end
+
+ def snippet_titles_count
+ @snippet_titles_count ||= snippet_titles.count
+ end
+
+ def snippet_blobs_count
+ @snippet_blobs_count ||= snippet_blobs.count
+ end
+
+ private
+
+ def snippet_titles
+ Snippet.where(id: limit_snippet_ids).search(query).order('updated_at DESC')
+ end
+
+ def snippet_blobs
+ search = Snippet.where(id: limit_snippet_ids).search_code(query)
+ search = search.order('updated_at DESC').to_a
+ snippets = []
+ search.each { |e| snippets << chunk_snippet(e) }
+ snippets
+ end
+
+ def default_scope
+ 'snippet_blobs'
+ end
+
+ # Get an array of line numbers surrounding a matching
+ # line, bounded by min/max.
+ #
+ # @returns Array of line numbers
+ def bounded_line_numbers(line, min, max)
+ lower = line - surrounding_lines > min ? line - surrounding_lines : min
+ upper = line + surrounding_lines < max ? line + surrounding_lines : max
+ (lower..upper).to_a
+ end
+
+ # Returns a sorted set of lines to be included in a snippet preview.
+ # This ensures matching adjacent lines do not display duplicated
+ # surrounding code.
+ #
+ # @returns Array, unique and sorted.
+ def matching_lines(lined_content)
+ used_lines = []
+ lined_content.each_with_index do |line, line_number|
+ used_lines.concat bounded_line_numbers(
+ line_number,
+ 0,
+ lined_content.size
+ ) if line.include?(query)
+ end
+
+ used_lines.uniq.sort
+ end
+
+ # 'Chunkify' entire snippet. Splits the snippet data into matching lines +
+ # surrounding_lines() worth of unmatching lines.
+ #
+ # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
+ def chunk_snippet(snippet)
+ lined_content = snippet.content.split("\n")
+ used_lines = matching_lines(lined_content)
+
+ snippet_chunk = []
+ snippet_chunks = []
+ snippet_start_line = 0
+ last_line = -1
+
+ # Go through each used line, and add consecutive lines as a single chunk
+ # to the snippet chunk array.
+ used_lines.each do |line_number|
+ if last_line < 0
+ # Start a new chunk.
+ snippet_start_line = line_number
+ snippet_chunk << lined_content[line_number]
+ elsif last_line == line_number - 1
+ # Consecutive line, continue chunk.
+ snippet_chunk << lined_content[line_number]
+ else
+ # Non-consecutive line, add chunk to chunk array.
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Start a new chunk.
+ snippet_chunk = [lined_content[line_number]]
+ snippet_start_line = line_number
+ end
+ last_line = line_number
+ end
+ # Add final chunk to chunk array
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Return snippet with chunk array
+ { snippet_object: snippet, snippet_chunks: snippet_chunks }
+ end
+
+ # Defines how many unmatching lines should be
+ # included around the matching lines in a snippet
+ def surrounding_lines
+ 3
+ end
+ end
+end
diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb
index 0846359f9b1..74b049b5143 100644
--- a/lib/gitlab/upgrader.rb
+++ b/lib/gitlab/upgrader.rb
@@ -43,7 +43,7 @@ module Gitlab
end
def latest_version_raw
- remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags origin))
+ remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
git_tags = remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
git_tags = git_tags.select { |version| version =~ /v\d\.\d\.\d\Z/ }
last_tag = git_tags.last.match(/v\d\.\d\.\d/).to_s
diff --git a/lib/gitlab/visibility_level.rb b/lib/gitlab/visibility_level.rb
index ea1319268f8..d0b6cde3c7e 100644
--- a/lib/gitlab/visibility_level.rb
+++ b/lib/gitlab/visibility_level.rb
@@ -23,7 +23,21 @@ module Gitlab
end
def allowed_for?(user, level)
- user.is_admin? || !Gitlab.config.gitlab.restricted_visibility_levels.include?(level)
+ user.is_admin? || allowed_level?(level)
+ end
+
+ # Level can be a string `"public"` or a value `20`, first check if valid,
+ # then check if the corresponding string appears in the config
+ def allowed_level?(level)
+ if options.has_key?(level.to_s)
+ non_restricted_level?(level)
+ elsif options.has_value?(level.to_i)
+ non_restricted_level?(options.key(level.to_i).downcase)
+ end
+ end
+
+ def non_restricted_level?(level)
+ ! Gitlab.config.gitlab.restricted_visibility_levels.include?(level)
end
end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 49306fb63da..49a68c62293 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -1,69 +1,85 @@
-# GITLAB
-# Maintainer: @randx
-
-# CHUNKED TRANSFER
-# It is a known issue that Git-over-HTTP requires chunked transfer encoding [0] which is not
-# supported by Nginx < 1.3.9 [1]. As a result, pushing a large object with Git (i.e. a single large file)
-# can lead to a 411 error. In theory you can get around this by tweaking this configuration file and either
-# - installing an old version of Nginx with the chunkin module [2] compiled in, or
-# - using a newer version of Nginx.
-#
-# At the time of writing we do not know if either of these theoretical solutions works. As a workaround
-# users can use Git over SSH to push large files.
-#
-# [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
-# [1] https://github.com/agentzh/chunkin-nginx-module#status
-# [2] https://github.com/agentzh/chunkin-nginx-module
+## GitLab
+## Maintainer: @randx
+##
+## Lines starting with two hashes (##) are comments with information.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
+##
+##################################
+## CHUNKED TRANSFER ##
+##################################
+##
+## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
+## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
+## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
+## around this by tweaking this configuration file and either:
+## - installing an old version of Nginx with the chunkin module [2] compiled in, or
+## - using a newer version of Nginx.
+##
+## At the time of writing we do not know if either of these theoretical solutions works.
+## As a workaround users can use Git over SSH to push large files.
+##
+## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
+## [1] https://github.com/agentzh/chunkin-nginx-module#status
+## [2] https://github.com/agentzh/chunkin-nginx-module
+##
+###################################
+## configuration ##
+###################################
+##
upstream gitlab {
- server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
+ server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
+## Normal HTTP host
server {
listen *:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
-
- # Increase this if you want to upload large attachments
- # Or if you want to accept large git objects over http
+
+ ## Increase this if you want to upload large attachments
+ ## Or if you want to accept large git objects over http
client_max_body_size 20m;
- # individual nginx logs for this gitlab vhost
+ ## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
location / {
- # serve static files from defined root folder;.
- # @gitlab is a named location for the upstream fallback, see below
+ ## Serve static files from defined root folder.
+ ## @gitlab is a named location for the upstream fallback, see below.
try_files $uri $uri/index.html $uri.html @gitlab;
}
- # if a file, which is not found in the root folder is requested,
- # then the proxy pass the request to the upsteam (gitlab unicorn)
+ ## If a file, which is not found in the root folder is requested,
+ ## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
- # If you use https make sure you disable gzip compression
- # to be safe against BREACH attack
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
# gzip off;
- proxy_read_timeout 300; # Some requests take more than 30 seconds.
- proxy_connect_timeout 300; # Some requests take more than 30 seconds.
- proxy_redirect off;
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Frame-Options SAMEORIGIN;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
- # Enable gzip compression as per rails guide: http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- # WARNING: If you are using relative urls do remove the block below
- # See config/application.rb under "Relative url support" for the list of
- # other files that need to be changed for relative url support
- location ~ ^/(assets)/ {
+ ## Enable gzip compression as per rails guide:
+ ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
+ ## WARNING: If you are using relative urls remove the block below
+ ## See config/application.rb under "Relative url support" for the list of
+ ## other files that need to be changed for relative url support
+ location ~ ^/(assets)/ {
root /home/git/gitlab/public;
gzip_static on; # to serve pre-gzipped version
expires max;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 54a4a080a9f..19409e41f40 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -6,8 +6,7 @@
## Modified from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
##
## Lines starting with two hashes (##) are comments with information.
-## Lines starting with one hash (#) are configuration parameters.
-## The last category can be commented/uncommented to your liking.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
##
##################################
## CHUNKED TRANSFER ##
@@ -20,44 +19,36 @@
## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx.
##
-## At the time of writing we do not know if either of these theoretical solutions works. As a workaround
-## users can use Git over SSH to push large files.
+## At the time of writing we do not know if either of these theoretical solutions works.
+## As a workaround users can use Git over SSH to push large files.
##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
## [1] https://github.com/agentzh/chunkin-nginx-module#status
## [2] https://github.com/agentzh/chunkin-nginx-module
##
-###################################
-## SSL file editing ##
-###################################
-##
-## Edit `gitlab-shell/config.yml`:
-## 1) Set "gitlab_url" param in `gitlab-shell/config.yml` to `https://git.example.com`
-## 2) Set "ca_file" to `/etc/nginx/ssl/gitlab.crt`
-## 3) Set "self_signed_cert" to `true`
-## Edit `gitlab/config/gitlab.yml`:
-## 1) Define port for http "port: 443"
-## 2) Enable https "https: true"
-## 3) Update ssl for gravatar "ssl_url: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm"
##
###################################
## SSL configuration ##
###################################
##
+## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab {
- server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
+ server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
-## This is a normal HTTP host which redirects all traffic to the HTTPS host.
+## Normal HTTP host
server {
listen *:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
+
+ ## Redirects all traffic to the HTTPS host
root /nowhere; ## root doesn't have to be a valid path since we are redirecting
- rewrite ^ https://$server_name$request_uri permanent;
+ rewrite ^ https://$server_name$request_uri? permanent;
}
+## HTTPS host
server {
listen 443 ssl;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
@@ -74,7 +65,7 @@ server {
ssl_certificate /etc/nginx/ssl/gitlab.crt;
ssl_certificate_key /etc/nginx/ssl/gitlab.key;
- ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
+ ssl_ciphers 'AES256+EECDH:AES256+EDH';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
@@ -82,9 +73,26 @@ server {
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security max-age=63072000;
- add_header X-Frame-Options DENY;
+ add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
+ ## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
+ ## Replace with your ssl_trusted_certificate. For more info see:
+ ## - https://medium.com/devops-programming/4445f4862461
+ ## - https://www.ruby-forum.com/topic/4419319
+ ## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
+ # ssl_stapling on;
+ # ssl_stapling_verify on;
+ # ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
+ # resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
+ # resolver_timeout 10s;
+
+ ## [Optional] Generate a stronger DHE parameter:
+ ## cd /etc/ssl/certs
+ ## sudo openssl dhparam -out dhparam.pem 4096
+ ##
+ # ssl_dhparam /etc/ssl/certs/dhparam.pem;
+
## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
@@ -96,10 +104,9 @@ server {
}
## If a file, which is not found in the root folder is requested,
- ## then the proxy pass the request to the upsteam (gitlab unicorn).
+ ## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
-
- ## If you use https make sure you disable gzip compression
+ ## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
@@ -121,7 +128,7 @@ server {
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- ## WARNING: If you are using relative urls do remove the block below
+ ## WARNING: If you are using relative urls remove the block below
## See config/application.rb under "Relative url support" for the list of
## other files that need to be changed for relative url support
location ~ ^/(assets)/ {
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 032ed5ee370..9ea5c55abd6 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -322,7 +322,7 @@ namespace :gitlab do
"core.autocrlf" => "input"
}
correct_options = options.map do |name, value|
- run(%W(git config --global --get #{name})).try(:squish) == value
+ run(%W(#{Gitlab.config.git.bin_path} config --global --get #{name})).try(:squish) == value
end
if correct_options.all?
@@ -330,9 +330,9 @@ namespace :gitlab do
else
puts "no".red
try_fixing_it(
- sudo_gitlab("git config --global user.name \"#{options["user.name"]}\""),
- sudo_gitlab("git config --global user.email \"#{options["user.email"]}\""),
- sudo_gitlab("git config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.name \"#{options["user.name"]}\""),
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global user.email \"#{options["user.email"]}\""),
+ sudo_gitlab("\"#{Gitlab.config.git.bin_path}\" config --global core.autocrlf \"#{options["core.autocrlf"]}\"")
)
for_more_information(
see_installation_guide_section "GitLab"
@@ -541,7 +541,7 @@ namespace :gitlab do
"sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}"
)
for_more_information(
- "#{gitlab_shell_path}/support/rewrite-hooks.sh"
+ "#{gitlab_shell_path}/bin/create-hooks"
)
fix_and_rerun
next
@@ -556,7 +556,7 @@ namespace :gitlab do
"sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}"
)
for_more_information(
- "lib/support/rewrite-hooks.sh"
+ "#{gitlab_shell_path}/bin/create-hooks"
)
fix_and_rerun
end
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index ff27e6a3066..ece3ad58385 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -8,7 +8,7 @@ namespace :gitlab do
args.with_defaults(tag: 'v' + default_version, repo: "https://gitlab.com/gitlab-org/gitlab-shell.git")
user = Settings.gitlab.user
- home_dir = Settings.gitlab.user_home
+ home_dir = Rails.env.test? ? Rails.root.join('tmp/tests') : Settings.gitlab.user_home
gitlab_url = Settings.gitlab.url
# gitlab-shell requires a / at the end of the url
gitlab_url += "/" unless gitlab_url.match(/\/$/)
diff --git a/lib/tasks/gitlab/sidekiq.rake b/lib/tasks/gitlab/sidekiq.rake
new file mode 100644
index 00000000000..7e2a6668e59
--- /dev/null
+++ b/lib/tasks/gitlab/sidekiq.rake
@@ -0,0 +1,47 @@
+namespace :gitlab do
+ namespace :sidekiq do
+ QUEUE = 'queue:post_receive'
+
+ desc 'Drop all Sidekiq PostReceive jobs for a given project'
+ task :drop_post_receive , [:project] => :environment do |t, args|
+ unless args.project.present?
+ abort "Please specify the project you want to drop PostReceive jobs for:\n rake gitlab:sidekiq:drop_post_receive[group/project]"
+ end
+ project_path = Project.find_with_namespace(args.project).repository.path_to_repo
+
+ Sidekiq.redis do |redis|
+ unless redis.exists(QUEUE)
+ abort "Queue #{QUEUE} is empty"
+ end
+
+ temp_queue = "#{QUEUE}_#{Time.now.to_i}"
+ redis.rename(QUEUE, temp_queue)
+
+ # At this point, then post_receive queue is empty. It may be receiving
+ # new jobs already. We will repopulate it with the old jobs, skipping the
+ # ones we want to drop.
+ dropped = 0
+ while (job = redis.lpop(temp_queue)) do
+ if repo_path(job) == project_path
+ dropped += 1
+ else
+ redis.rpush(QUEUE, job)
+ end
+ end
+ # The temp_queue will delete itself after we have popped all elements
+ # from it
+
+ puts "Dropped #{dropped} jobs containing #{project_path} from #{QUEUE}"
+ end
+ end
+
+ def repo_path(job)
+ job_args = JSON.parse(job)['args']
+ if job_args
+ job_args.first
+ else
+ nil
+ end
+ end
+ end
+end