summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/gitlab/access.rb8
-rw-r--r--lib/gitlab/award_emoji.rb24
-rw-r--r--lib/gitlab/checks/change_access.rb96
-rw-r--r--lib/gitlab/checks/force_push.rb17
-rw-r--r--lib/gitlab/checks/matching_merge_request.rb18
-rw-r--r--lib/gitlab/diff/file.rb6
-rw-r--r--lib/gitlab/force_push_check.rb15
-rw-r--r--lib/gitlab/git_access.rb143
-rw-r--r--lib/gitlab/git_access_wiki.rb2
-rw-r--r--lib/gitlab/import_export.rb2
-rw-r--r--lib/gitlab/import_export/import_export.yml6
-rw-r--r--lib/gitlab/import_export/relation_factory.rb5
-rw-r--r--lib/gitlab/user_access.rb48
-rw-r--r--lib/tasks/gemojione.rake17
15 files changed, 243 insertions, 166 deletions
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 77e407b54c5..73557cf7db6 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -17,7 +17,7 @@ module API
def current_user
@current_user ||= (find_user_by_private_token || doorkeeper_guard)
- unless @current_user && Gitlab::UserAccess.allowed?(@current_user)
+ unless @current_user && Gitlab::UserAccess.new(@current_user).allowed?
return nil
end
diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb
index 831f1e635ba..de41ea415a6 100644
--- a/lib/gitlab/access.rb
+++ b/lib/gitlab/access.rb
@@ -14,9 +14,10 @@ module Gitlab
OWNER = 50
# Branch protection settings
- PROTECTION_NONE = 0
- PROTECTION_DEV_CAN_PUSH = 1
- PROTECTION_FULL = 2
+ PROTECTION_NONE = 0
+ PROTECTION_DEV_CAN_PUSH = 1
+ PROTECTION_FULL = 2
+ PROTECTION_DEV_CAN_MERGE = 3
class << self
def values
@@ -54,6 +55,7 @@ module Gitlab
def protection_options
{
"Not protected: Both developers and masters can push new commits, force push, or delete the branch." => PROTECTION_NONE,
+ "Protected against pushes: Developers cannot push new commits, but are allowed to accept merge requests to the branch." => PROTECTION_DEV_CAN_MERGE,
"Partially protected: Developers can push new commits, but cannot force push or delete the branch. Masters can do all of those." => PROTECTION_DEV_CAN_PUSH,
"Fully protected: Developers cannot push new commits, force push, or delete the branch. Only masters can do any of those." => PROTECTION_FULL,
}
diff --git a/lib/gitlab/award_emoji.rb b/lib/gitlab/award_emoji.rb
index c94bfc0e65f..39b43ab5489 100644
--- a/lib/gitlab/award_emoji.rb
+++ b/lib/gitlab/award_emoji.rb
@@ -1,24 +1,14 @@
module Gitlab
class AwardEmoji
CATEGORIES = {
- other: "Other",
objects: "Objects",
- places: "Places",
- travel_places: "Travel",
- emoticons: "Emoticons",
- objects_symbols: "Symbols",
+ travel: "Travel",
+ symbols: "Symbols",
nature: "Nature",
- celebration: "Celebration",
people: "People",
activity: "Activity",
flags: "Flags",
- food_drink: "Food"
- }.with_indifferent_access
-
- CATEGORY_ALIASES = {
- symbols: "objects_symbols",
- foods: "food_drink",
- travel: "travel_places"
+ food: "Food"
}.with_indifferent_access
def self.normalize_emoji_name(name)
@@ -35,7 +25,7 @@ module Gitlab
# Skip Fitzpatrick(tone) modifiers
next if data["category"] == "modifier"
- category = CATEGORY_ALIASES[data["category"]] || data["category"]
+ category = data["category"]
@emoji_by_category[category] << data
end
@@ -57,9 +47,9 @@ module Gitlab
def self.aliases
@aliases ||=
begin
- json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json' )
- JSON.parse(File.read(json_path))
- end
+ json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
+ JSON.parse(File.read(json_path))
+ end
end
# Returns an Array of Emoji names and their asset URLs.
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
new file mode 100644
index 00000000000..5551fac4b8b
--- /dev/null
+++ b/lib/gitlab/checks/change_access.rb
@@ -0,0 +1,96 @@
+module Gitlab
+ module Checks
+ class ChangeAccess
+ attr_reader :user_access, :project
+
+ def initialize(change, user_access:, project:)
+ @oldrev, @newrev, @ref = change.split(' ')
+ @branch_name = branch_name(@ref)
+ @user_access = user_access
+ @project = project
+ end
+
+ def exec
+ error = protected_branch_checks || tag_checks || push_checks
+
+ if error
+ GitAccessStatus.new(false, error)
+ else
+ GitAccessStatus.new(true)
+ end
+ end
+
+ protected
+
+ def protected_branch_checks
+ return unless project.protected_branch?(@branch_name)
+
+ if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches)
+ return "You are not allowed to force push code to a protected branch on this project."
+ elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches)
+ return "You are not allowed to delete protected branches from this project."
+ end
+
+ if matching_merge_request?
+ if user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name)
+ return
+ else
+ "You are not allowed to merge code into protected branches on this project."
+ end
+ else
+ if user_access.can_push_to_branch?(@branch_name)
+ return
+ else
+ "You are not allowed to push code to protected branches on this project."
+ end
+ end
+ end
+
+ def tag_checks
+ tag_ref = tag_name(@ref)
+
+ if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project)
+ "You are not allowed to change existing tags on this project."
+ end
+ end
+
+ def push_checks
+ if user_access.cannot_do_action?(:push_code)
+ "You are not allowed to push code to this project."
+ end
+ end
+
+ private
+
+ def protected_tag?(tag_name)
+ project.repository.tag_exists?(tag_name)
+ end
+
+ def forced_push?
+ Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev)
+ end
+
+ def matching_merge_request?
+ Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match?
+ end
+
+ def branch_name(ref)
+ ref = @ref.to_s
+ if Gitlab::Git.branch_ref?(ref)
+ Gitlab::Git.ref_name(ref)
+ else
+ nil
+ end
+ end
+
+ def tag_name(ref)
+ ref = @ref.to_s
+ if Gitlab::Git.tag_ref?(ref)
+ Gitlab::Git.ref_name(ref)
+ else
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/checks/force_push.rb b/lib/gitlab/checks/force_push.rb
new file mode 100644
index 00000000000..dfa83a0eab3
--- /dev/null
+++ b/lib/gitlab/checks/force_push.rb
@@ -0,0 +1,17 @@
+module Gitlab
+ module Checks
+ class ForcePush
+ def self.force_push?(project, oldrev, newrev)
+ return false if project.empty_repo?
+
+ # Created or deleted branch
+ if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
+ false
+ else
+ missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
+ missed_refs.split("\n").size > 0
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/checks/matching_merge_request.rb b/lib/gitlab/checks/matching_merge_request.rb
new file mode 100644
index 00000000000..849848515da
--- /dev/null
+++ b/lib/gitlab/checks/matching_merge_request.rb
@@ -0,0 +1,18 @@
+module Gitlab
+ module Checks
+ class MatchingMergeRequest
+ def initialize(newrev, branch_name, project)
+ @newrev = newrev
+ @branch_name = branch_name
+ @project = project
+ end
+
+ def match?
+ @project.merge_requests
+ .with_state(:locked)
+ .where(in_progress_merge_commit_sha: @newrev, target_branch: @branch_name)
+ .exists?
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 7e01f7b61fb..b09ca1fb8b0 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -5,7 +5,7 @@ module Gitlab
delegate :new_file, :deleted_file, :renamed_file,
:old_path, :new_path, :a_mode, :b_mode,
- :submodule?, :too_large?, to: :diff, prefix: false
+ :submodule?, :too_large?, :collapsed?, to: :diff, prefix: false
def initialize(diff, repository:, diff_refs: nil)
@diff = diff
@@ -68,10 +68,6 @@ module Gitlab
@lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a
end
- def collapsed_by_default?
- diff.diff.bytesize > 10240 # 10 KB
- end
-
def highlighted_diff_lines
@highlighted_diff_lines ||= Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
end
diff --git a/lib/gitlab/force_push_check.rb b/lib/gitlab/force_push_check.rb
deleted file mode 100644
index 93c6a5bb7f5..00000000000
--- a/lib/gitlab/force_push_check.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module Gitlab
- class ForcePushCheck
- def self.force_push?(project, oldrev, newrev)
- return false if project.empty_repo?
-
- # Created or deleted branch
- if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
- false
- else
- missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
- missed_refs.split("\n").size > 0
- end
- end
- end
-end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 7679c7e4bb8..308f23bc9bc 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -1,52 +1,17 @@
+# Check a user's access to perform a git action. All public methods in this
+# class return an instance of `GitlabAccessStatus`
module Gitlab
class GitAccess
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
PUSH_COMMANDS = %w{ git-receive-pack }
- attr_reader :actor, :project, :protocol
+ attr_reader :actor, :project, :protocol, :user_access
def initialize(actor, project, protocol)
@actor = actor
@project = project
@protocol = protocol
- end
-
- def user
- return @user if defined?(@user)
-
- @user =
- case actor
- when User
- actor
- when DeployKey
- nil
- when Key
- actor.user
- end
- end
-
- def deploy_key
- actor if actor.is_a?(DeployKey)
- end
-
- def can_push_to_branch?(ref)
- return false unless user
-
- if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref)
- user.can?(:push_code_to_protected_branches, project)
- else
- user.can?(:push_code, project)
- end
- end
-
- def can_read_project?
- if user
- user.can?(:read_project, project)
- elsif deploy_key
- deploy_key.projects.include?(project)
- else
- false
- end
+ @user_access = UserAccess.new(user, project: project)
end
def check(cmd, changes = nil)
@@ -56,11 +21,11 @@ module Gitlab
return build_status_object(false, "No user or key was provided.")
end
- if user && !user_allowed?
+ if user && !user_access.allowed?
return build_status_object(false, "Your account has been blocked.")
end
- unless project && can_read_project?
+ unless project && (user_access.can_read_project? || deploy_key_can_read_project?)
return build_status_object(false, 'The project you were looking for could not be found.')
end
@@ -95,7 +60,7 @@ module Gitlab
end
def user_download_access_check
- unless user.can?(:download_code, project)
+ unless user_access.can_do_action?(:download_code)
return build_status_object(false, "You are not allowed to download code from this project.")
end
@@ -125,46 +90,8 @@ module Gitlab
build_status_object(true)
end
- def can_user_do_action?(action)
- @permission_cache ||= {}
- @permission_cache[action] ||= user.can?(action, project)
- end
-
def change_access_check(change)
- oldrev, newrev, ref = change.split(' ')
-
- action =
- if project.protected_branch?(branch_name(ref))
- protected_branch_action(oldrev, newrev, branch_name(ref))
- elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref)
- # Prevent any changes to existing git tag unless user has permissions
- :admin_project
- else
- :push_code
- end
-
- unless can_user_do_action?(action)
- status =
- case action
- when :force_push_code_to_protected_branches
- build_status_object(false, "You are not allowed to force push code to a protected branch on this project.")
- when :remove_protected_branches
- build_status_object(false, "You are not allowed to deleted protected branches from this project.")
- when :push_code_to_protected_branches
- build_status_object(false, "You are not allowed to push code to protected branches on this project.")
- when :admin_project
- build_status_object(false, "You are not allowed to change existing tags on this project.")
- else # :push_code
- build_status_object(false, "You are not allowed to push code to this project.")
- end
- return status
- end
-
- build_status_object(true)
- end
-
- def forced_push?(oldrev, newrev)
- Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev)
+ Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec
end
def protocol_allowed?
@@ -173,48 +100,38 @@ module Gitlab
private
- def protected_branch_action(oldrev, newrev, branch_name)
- # we dont allow force push to protected branch
- if forced_push?(oldrev, newrev)
- :force_push_code_to_protected_branches
- elsif Gitlab::Git.blank_ref?(newrev)
- # and we dont allow remove of protected branch
- :remove_protected_branches
- elsif project.developers_can_push_to_protected_branch?(branch_name)
- :push_code
- else
- :push_code_to_protected_branches
- end
+ def matching_merge_request?(newrev, branch_name)
+ Checks::MatchingMergeRequest.new(newrev, branch_name, project).match?
end
- def protected_tag?(tag_name)
- project.repository.tag_exists?(tag_name)
- end
-
- def user_allowed?
- Gitlab::UserAccess.allowed?(user)
- end
-
- def branch_name(ref)
- ref = ref.to_s
- if Gitlab::Git.branch_ref?(ref)
- Gitlab::Git.ref_name(ref)
- else
- nil
- end
+ def deploy_key
+ actor if actor.is_a?(DeployKey)
end
- def tag_name(ref)
- ref = ref.to_s
- if Gitlab::Git.tag_ref?(ref)
- Gitlab::Git.ref_name(ref)
+ def deploy_key_can_read_project?
+ if deploy_key
+ deploy_key.projects.include?(project)
else
- nil
+ false
end
end
protected
+ def user
+ return @user if defined?(@user)
+
+ @user =
+ case actor
+ when User
+ actor
+ when DeployKey
+ nil
+ when Key
+ actor.user
+ end
+ end
+
def build_status_object(status, message = '')
GitAccessStatus.new(status, message)
end
diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb
index 8672cbc0ec4..f71d3575909 100644
--- a/lib/gitlab/git_access_wiki.rb
+++ b/lib/gitlab/git_access_wiki.rb
@@ -1,7 +1,7 @@
module Gitlab
class GitAccessWiki < GitAccess
def change_access_check(change)
- if user.can?(:create_wiki, project)
+ if user_access.can_do_action?(:create_wiki)
build_status_object(true)
else
build_status_object(false, "You are not allowed to write to this project's wiki.")
diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb
index bab2ea73c4f..d6d14bd98a0 100644
--- a/lib/gitlab/import_export.rb
+++ b/lib/gitlab/import_export.rb
@@ -2,7 +2,7 @@ module Gitlab
module ImportExport
extend self
- VERSION = '0.1.1'
+ VERSION = '0.1.2'
FILENAME_LIMIT = 50
def export_path(relative_path:)
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 05f4ad527ac..15afe8174a4 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -53,7 +53,11 @@ included_attributes:
excluded_attributes:
snippets:
- :expired_at
+ merge_request_diff:
+ - :st_diffs
methods:
statuses:
- - :type \ No newline at end of file
+ - :type
+ merge_request_diff:
+ - :utf8_st_diffs \ No newline at end of file
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 6ba25a31641..e41c7e6bf4f 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -33,6 +33,7 @@ module Gitlab
update_project_references
reset_ci_tokens if @relation_name == 'Ci::Trigger'
@relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data']
+ set_st_diffs if @relation_name == :merge_request_diff
generate_imported_object
end
@@ -129,6 +130,10 @@ module Gitlab
def parsed_relation_hash
@relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) }
end
+
+ def set_st_diffs
+ @relation_hash['st_diffs'] = @relation_hash.delete('utf8_st_diffs')
+ end
end
end
end
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index d1b42c1f9b9..c0f85e9b3a8 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -1,7 +1,23 @@
module Gitlab
- module UserAccess
- def self.allowed?(user)
- return false if user.blocked?
+ class UserAccess
+ attr_reader :user, :project
+
+ def initialize(user, project: nil)
+ @user = user
+ @project = project
+ end
+
+ def can_do_action?(action)
+ @permission_cache ||= {}
+ @permission_cache[action] ||= user.can?(action, project)
+ end
+
+ def cannot_do_action?(action)
+ !can_do_action?(action)
+ end
+
+ def allowed?
+ return false if user.blank? || user.blocked?
if user.requires_ldap_check? && user.try_obtain_ldap_lease
return false unless Gitlab::LDAP::Access.allowed?(user)
@@ -9,5 +25,31 @@ module Gitlab
true
end
+
+ def can_push_to_branch?(ref)
+ return false unless user
+
+ if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref)
+ user.can?(:push_code_to_protected_branches, project)
+ else
+ user.can?(:push_code, project)
+ end
+ end
+
+ def can_merge_to_branch?(ref)
+ return false unless user
+
+ if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref)
+ user.can?(:push_code_to_protected_branches, project)
+ else
+ user.can?(:push_code, project)
+ end
+ end
+
+ def can_read_project?
+ return false unless user
+
+ user.can?(:read_project, project)
+ end
end
end
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
index e930ace1041..993112aee3b 100644
--- a/lib/tasks/gemojione.rake
+++ b/lib/tasks/gemojione.rake
@@ -4,7 +4,7 @@ namespace :gemojione do
require 'digest/sha2'
require 'json'
- dir = Gemojione.index.images_path
+ dir = Gemojione.images_path
digests = []
aliases = Hash.new { |hash, key| hash[key] = [] }
aliases_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
@@ -50,9 +50,14 @@ namespace :gemojione do
SIZE = 20
RETINA = SIZE * 2
+ # Update these values to the width and height of the spritesheet when
+ # new emoji are added.
+ SPRITESHEET_WIDTH = 860
+ SPRITESHEET_HEIGHT = 840
+
Dir.mktmpdir do |tmpdir|
# Copy the Gemojione assets to the temporary folder for resizing
- FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
+ FileUtils.cp_r(Gemojione.images_path, tmpdir)
Dir.chdir(tmpdir) do
Dir["**/*.png"].each do |png|
@@ -64,7 +69,7 @@ namespace :gemojione do
# Combine the resized assets into a packed sprite and re-generate the SCSS
SpriteFactory.cssurl = "image-url('$IMAGE')"
- SpriteFactory.run!(File.join(tmpdir, 'images'), {
+ SpriteFactory.run!(File.join(tmpdir, 'png'), {
output_style: style_path,
output_image: "app/assets/images/emoji.png",
selector: '.emoji-',
@@ -97,7 +102,7 @@ namespace :gemojione do
only screen and (min-resolution: 192dpi),
only screen and (min-resolution: 2dppx) {
background-image: image-url('emoji@2x.png');
- background-size: 840px 820px;
+ background-size: #{SPRITESHEET_WIDTH}px #{SPRITESHEET_HEIGHT}px;
}
}
CSS
@@ -107,7 +112,7 @@ namespace :gemojione do
# Now do it again but for Retina
Dir.mktmpdir do |tmpdir|
# Copy the Gemojione assets to the temporary folder for resizing
- FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
+ FileUtils.cp_r(Gemojione.images_path, tmpdir)
Dir.chdir(tmpdir) do
Dir["**/*.png"].each do |png|
@@ -116,7 +121,7 @@ namespace :gemojione do
end
# Combine the resized assets into a packed sprite and re-generate the SCSS
- SpriteFactory.run!(File.join(tmpdir, 'images'), {
+ SpriteFactory.run!(File.join(tmpdir), {
output_image: "app/assets/images/emoji@2x.png",
style: false,
nocomments: true,