summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorZeger-Jan van de Weg <git@zjvandeweg.nl>2017-09-04 09:28:46 +0200
committerZeger-Jan van de Weg <git@zjvandeweg.nl>2017-09-04 09:28:46 +0200
commita315e6025c702985b2f6390b29508de39383f52d (patch)
treef0d07d955092e4a218346c41f2942131dfcef91a /lib
parent78dad4cf321eb84aa5decdea34704145adca0c3e (diff)
parentfd54a4678f23c9e18ce46b3803e5e57ffa1199a3 (diff)
downloadgitlab-ce-a315e6025c702985b2f6390b29508de39383f52d.tar.gz
Merge branch 'master' into zj-auto-devops-table
Diffstat (limited to 'lib')
-rw-r--r--lib/api/access_requests.rb2
-rw-r--r--lib/api/award_emoji.rb2
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/deploy_keys.rb2
-rw-r--r--lib/api/deployments.rb2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/environments.rb2
-rw-r--r--lib/api/events.rb2
-rw-r--r--lib/api/group_milestones.rb2
-rw-r--r--lib/api/group_variables.rb2
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/helpers/internal_helpers.rb4
-rw-r--r--lib/api/internal.rb17
-rw-r--r--lib/api/issues.rb4
-rw-r--r--lib/api/jobs.rb2
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/members.rb2
-rw-r--r--lib/api/merge_request_diffs.rb2
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/notes.rb2
-rw-r--r--lib/api/notification_settings.rb2
-rw-r--r--lib/api/pipeline_schedules.rb2
-rw-r--r--lib/api/pipelines.rb2
-rw-r--r--lib/api/project_hooks.rb2
-rw-r--r--lib/api/project_milestones.rb2
-rw-r--r--lib/api/project_snippets.rb2
-rw-r--r--lib/api/projects.rb4
-rw-r--r--lib/api/repositories.rb2
-rw-r--r--lib/api/runners.rb2
-rw-r--r--lib/api/services.rb4
-rw-r--r--lib/api/settings.rb7
-rw-r--r--lib/api/subscriptions.rb2
-rw-r--r--lib/api/todos.rb2
-rw-r--r--lib/api/triggers.rb2
-rw-r--r--lib/api/variables.rb2
-rw-r--r--lib/gitlab/auth.rb4
-rw-r--r--lib/gitlab/git/repository.rb10
-rw-r--r--lib/gitlab/git_access.rb9
-rw-r--r--lib/gitlab/i18n/metadata_entry.rb27
-rw-r--r--lib/gitlab/i18n/po_linter.rb216
-rw-r--r--lib/gitlab/i18n/translation_entry.rb92
-rw-r--r--lib/gitlab/key_fingerprint.rb48
-rw-r--r--lib/gitlab/reference_counter.rb44
-rw-r--r--lib/gitlab/sentry.rb2
-rw-r--r--lib/gitlab/ssh_public_key.rb71
-rw-r--r--lib/gitlab/utils.rb4
-rw-r--r--lib/gitlab/workhorse.rb5
-rw-r--r--lib/tasks/gettext.rake40
49 files changed, 578 insertions, 96 deletions
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 4fa9b2b2494..374b611f55e 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -10,7 +10,7 @@ module API
params do
requires :id, type: String, desc: "The #{source_type} ID"
end
- resource source_type.pluralize, requirements: { id: %r{[^/]+} } do
+ resource source_type.pluralize, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc "Gets a list of access requests for a #{source_type}." do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index 8e3851640da..c3d93996816 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -12,7 +12,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
AWARDABLES.each do |awardable_params|
awardable_string = awardable_params[:type].pluralize
awardable_id_string = "#{awardable_params[:type]}_#{awardable_params[:find_by]}"
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 0d11c5fc971..366b0dc9a6f 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all project boards' do
detail 'This feature was introduced in 8.13'
success Entities::Board
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 485b680cd5f..78e889a4c35 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -5,7 +5,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
include PaginationParams
before { authenticate! }
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index f405c341398..281269b1190 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -17,7 +17,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of the project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
before { authorize_admin_project }
desc "Get a specific project's deploy keys" do
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 46b936897f6..1efee9a1324 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -8,7 +8,7 @@ module API
params do
requires :id, type: String, desc: 'The project ID'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all deployments of the project' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::Deployment
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 803b48dd88a..9df9a515990 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1,11 +1,11 @@
module API
module Entities
class UserSafe < Grape::Entity
- expose :name, :username
+ expose :id, :name, :username
end
class UserBasic < UserSafe
- expose :id, :state
+ expose :state
expose :avatar_url do |user, options|
user.avatar_url(only_path: false)
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index e33269f9483..5c63ec028d9 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -9,7 +9,7 @@ module API
params do
requires :id, type: String, desc: 'The project ID'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all environments of the project' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::Environment
diff --git a/lib/api/events.rb b/lib/api/events.rb
index dabdf579119..b0713ff1d54 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -67,7 +67,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc "List a Project's visible events" do
success Entities::Event
end
diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb
index b85eb59dc0a..93fa0b95857 100644
--- a/lib/api/group_milestones.rb
+++ b/lib/api/group_milestones.rb
@@ -10,7 +10,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a group'
end
- resource :groups, requirements: { id: %r{[^/]+} } do
+ resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of group milestones' do
success Entities::Milestone
end
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index 25152f30998..92800ce6450 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -9,7 +9,7 @@ module API
requires :id, type: String, desc: 'The ID of a group'
end
- resource :groups, requirements: { id: %r{[^/]+} } do
+ resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get group-level variables' do
success Entities::Variable
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 8c494a54329..31a918eda60 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -89,7 +89,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a group'
end
- resource :groups, requirements: { id: %r{[^/]+} } do
+ resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Update a group. Available only for users who can administrate groups.' do
success Entities::Group
end
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index ecb79317093..f57ff0f2632 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -42,6 +42,10 @@ module API
::Users::ActivityService.new(actor, 'Git SSH').execute if commands.include?(params[:action])
end
+ def merge_request_urls
+ ::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
+ end
+
private
def set_project
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 8b007869dc3..622bd9650e4 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -68,7 +68,7 @@ module API
end
get "/merge_request_urls" do
- ::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
+ merge_request_urls
end
#
@@ -155,6 +155,21 @@ module API
# render_api_error!(e, 500)
# end
end
+
+ post '/post_receive' do
+ status 200
+
+ PostReceive.perform_async(params[:gl_repository], params[:identifier],
+ params[:changes])
+ broadcast_message = BroadcastMessage.current&.last&.message
+ reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
+
+ {
+ merge_request_urls: merge_request_urls,
+ broadcast_message: broadcast_message,
+ reference_counter_decreased: reference_counter_decreased
+ }
+ end
end
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 0297023226f..e4c2c390853 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -81,7 +81,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a group'
end
- resource :groups, requirements: { id: %r{[^/]+} } do
+ resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of group issues' do
success Entities::IssueBasic
end
@@ -108,7 +108,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
include TimeTrackingEndpoints
desc 'Get a list of project issues' do
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index a40018b214e..5bab96398fd 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
helpers do
params :optional_scope do
optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index c0cf618ee8d..e41a1720ac1 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the project' do
success Entities::Label
end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index a5d3d7f25a0..22e4bdead41 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -10,7 +10,7 @@ module API
params do
requires :id, type: String, desc: "The #{source_type} ID"
end
- resource source_type.pluralize, requirements: { id: %r{[^/]+} } do
+ resource source_type.pluralize, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Gets a list of group or project members viewable by the authenticated user.' do
success Entities::Member
end
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index 4b79eac2b8b..c3affcc6c6b 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -8,7 +8,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of merge request diff versions' do
detail 'This feature was introduced in GitLab 8.12.'
success Entities::MergeRequestDiff
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index eec8d9357aa..7bcbf9f20ff 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -72,7 +72,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
include TimeTrackingEndpoints
helpers do
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index e116448c15b..d6e7203adaf 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -9,7 +9,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
NOTEABLE_TYPES.each do |noteable_type|
noteables_str = noteable_type.to_s.underscore.pluralize
diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb
index 5d113c94b22..bcc0833aa5c 100644
--- a/lib/api/notification_settings.rb
+++ b/lib/api/notification_settings.rb
@@ -54,7 +54,7 @@ module API
params do
requires :id, type: String, desc: "The #{source_type} ID"
end
- resource source_type.pluralize, requirements: { id: %r{[^/]+} } do
+ resource source_type.pluralize, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc "Get #{source_type} level notification level settings, defaults to Global" do
detail 'This feature was introduced in GitLab 8.12'
success Entities::NotificationSetting
diff --git a/lib/api/pipeline_schedules.rb b/lib/api/pipeline_schedules.rb
index e3123ef4e2d..ef01cbc7875 100644
--- a/lib/api/pipeline_schedules.rb
+++ b/lib/api/pipeline_schedules.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all pipeline schedules' do
success Entities::PipelineSchedule
end
diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb
index e505cae3992..74b3376a1f3 100644
--- a/lib/api/pipelines.rb
+++ b/lib/api/pipelines.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The project ID'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get all Pipelines of the project' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::PipelineBasic
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 5b457bbe639..86066e2b58f 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -24,7 +24,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get project hooks' do
success Entities::ProjectHook
end
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 451998c726a..0cb209a02d0 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -10,7 +10,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of project milestones' do
success Entities::Milestone
end
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 704e8c6718d..2ccda1c1aa1 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -7,7 +7,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
helpers do
def handle_project_member_errors(errors)
if errors[:project_access].any?
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 78d900984ac..4845242a173 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -95,7 +95,7 @@ module API
end
end
- resource :users, requirements: { user_id: %r{[^/]+} } do
+ resource :users, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a user projects' do
success Entities::BasicProjectDetails
end
@@ -183,7 +183,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a single project' do
success Entities::ProjectWithAccess
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 14d2bff9cb5..2255fb1b70d 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -9,7 +9,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
helpers do
def handle_project_member_errors(errors)
if errors[:project_access].any?
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index 68c2120cc15..1ea9a7918d7 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -87,7 +87,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
before { authorize_admin_project }
desc 'Get runners available for project' do
diff --git a/lib/api/services.rb b/lib/api/services.rb
index ff9ddd44439..2cbd0517dc3 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -601,7 +601,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
before { authenticate! }
before { authorize_admin_project }
@@ -691,7 +691,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc "Trigger a slash command for #{service_slug}" do
detail 'Added in GitLab 8.13'
end
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 667ba468ce6..851b226e9e5 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -122,6 +122,13 @@ module API
optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.'
optional :polling_interval_multiplier, type: BigDecimal, desc: 'Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling.'
+ ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
+ optional :"#{type}_key_restriction",
+ type: Integer,
+ values: KeyRestrictionValidator.supported_key_restrictions(type),
+ desc: "Restrictions on the complexity of uploaded #{type.upcase} keys. A value of #{ApplicationSetting::FORBIDDEN_KEY_VALUE} disables all #{type.upcase} keys."
+ end
+
optional(*::ApplicationSettingsHelper.visible_attributes)
at_least_one_of(*::ApplicationSettingsHelper.visible_attributes)
end
diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb
index 91567909998..b3e1e23031a 100644
--- a/lib/api/subscriptions.rb
+++ b/lib/api/subscriptions.rb
@@ -12,7 +12,7 @@ module API
requires :id, type: String, desc: 'The ID of a project'
requires :subscribable_id, type: String, desc: 'The ID of a resource'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
subscribable_types.each do |type, finder|
type_singularized = type.singularize
entity_class = Entities.const_get(type_singularized.camelcase)
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index 55191169dd4..ffccfebe752 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -12,7 +12,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
ISSUABLE_TYPES.each do |type, finder|
type_id_str = "#{type.singularize}_iid".to_sym
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index c9fee7e5193..dd6801664b1 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -5,7 +5,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Trigger a GitLab project pipeline' do
success Entities::Pipeline
end
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index da71787abab..d08876ae1b9 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -9,7 +9,7 @@ module API
requires :id, type: String, desc: 'The ID of a project'
end
- resource :projects, requirements: { id: %r{[^/]+} } do
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get project variables' do
success Entities::Variable
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 1790f380c33..3fd81759d25 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -50,10 +50,6 @@ module Gitlab
# Avoid resource intensive login checks if password is not provided
return unless password.present?
- # Nothing to do here if internal auth is disabled and LDAP is
- # not configured
- return unless current_application_settings.password_authentication_enabled? || Gitlab::LDAP::Config.enabled?
-
Gitlab::Auth::UniqueIpsLimiter.limit_user! do
user = User.by_login(login)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 554e40dc8a6..8709f82bcc4 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -250,11 +250,17 @@ module Gitlab
branch_names + tag_names
end
+ def delete_all_refs_except(prefixes)
+ delete_refs(*all_ref_names_except(prefixes))
+ end
+
# Returns an Array of all ref names, except when it's matching pattern
#
# regexp - The pattern for ref names we don't want
- def all_ref_names_except(regexp)
- rugged.references.reject { |ref| ref.name =~ regexp }.map(&:name)
+ def all_ref_names_except(prefixes)
+ rugged.references.reject do |ref|
+ prefixes.any? { |p| ref.name.start_with?(p) }
+ end.map(&:name)
end
# Discovers the default branch based on the repository's available branches
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 3e8b83c0f90..62d1ecae676 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -35,6 +35,7 @@ module Gitlab
def check(cmd, changes)
check_protocol!
+ check_valid_actor!
check_active_user!
check_project_accessibility!
check_project_moved!
@@ -70,6 +71,14 @@ module Gitlab
private
+ def check_valid_actor!
+ return unless actor.is_a?(Key)
+
+ unless actor.valid?
+ raise UnauthorizedError, "Your SSH key #{actor.errors[:key].first}."
+ end
+ end
+
def check_protocol!
unless protocol_allowed?
raise UnauthorizedError, "Git access over #{protocol.upcase} is not allowed"
diff --git a/lib/gitlab/i18n/metadata_entry.rb b/lib/gitlab/i18n/metadata_entry.rb
new file mode 100644
index 00000000000..35d57459a3d
--- /dev/null
+++ b/lib/gitlab/i18n/metadata_entry.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ module I18n
+ class MetadataEntry
+ attr_reader :entry_data
+
+ def initialize(entry_data)
+ @entry_data = entry_data
+ end
+
+ def expected_plurals
+ return nil unless plural_information
+
+ plural_information['nplurals'].to_i
+ end
+
+ private
+
+ def plural_information
+ return @plural_information if defined?(@plural_information)
+
+ if plural_line = entry_data[:msgstr].detect { |metadata_line| metadata_line.starts_with?('Plural-Forms: ') }
+ @plural_information = Hash[plural_line.scan(/(\w+)=([^;\n]+)/)]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/i18n/po_linter.rb b/lib/gitlab/i18n/po_linter.rb
new file mode 100644
index 00000000000..2e02787a4f4
--- /dev/null
+++ b/lib/gitlab/i18n/po_linter.rb
@@ -0,0 +1,216 @@
+require 'simple_po_parser'
+
+module Gitlab
+ module I18n
+ class PoLinter
+ attr_reader :po_path, :translation_entries, :metadata_entry, :locale
+
+ VARIABLE_REGEX = /%{\w*}|%[a-z]/.freeze
+
+ def initialize(po_path, locale = I18n.locale.to_s)
+ @po_path = po_path
+ @locale = locale
+ end
+
+ def errors
+ @errors ||= validate_po
+ end
+
+ def validate_po
+ if parse_error = parse_po
+ return 'PO-syntax errors' => [parse_error]
+ end
+
+ validate_entries
+ end
+
+ def parse_po
+ entries = SimplePoParser.parse(po_path)
+
+ # The first entry is the metadata entry if there is one.
+ # This is an entry when empty `msgid`
+ if entries.first[:msgid].empty?
+ @metadata_entry = Gitlab::I18n::MetadataEntry.new(entries.shift)
+ else
+ return 'Missing metadata entry.'
+ end
+
+ @translation_entries = entries.map do |entry_data|
+ Gitlab::I18n::TranslationEntry.new(entry_data, metadata_entry.expected_plurals)
+ end
+
+ nil
+ rescue SimplePoParser::ParserError => e
+ @translation_entries = []
+ e.message
+ end
+
+ def validate_entries
+ errors = {}
+
+ translation_entries.each do |entry|
+ errors_for_entry = validate_entry(entry)
+ errors[join_message(entry.msgid)] = errors_for_entry if errors_for_entry.any?
+ end
+
+ errors
+ end
+
+ def validate_entry(entry)
+ errors = []
+
+ validate_flags(errors, entry)
+ validate_variables(errors, entry)
+ validate_newlines(errors, entry)
+ validate_number_of_plurals(errors, entry)
+ validate_unescaped_chars(errors, entry)
+
+ errors
+ end
+
+ def validate_unescaped_chars(errors, entry)
+ if entry.msgid_contains_unescaped_chars?
+ errors << 'contains unescaped `%`, escape it using `%%`'
+ end
+
+ if entry.plural_id_contains_unescaped_chars?
+ errors << 'plural id contains unescaped `%`, escape it using `%%`'
+ end
+
+ if entry.translations_contain_unescaped_chars?
+ errors << 'translation contains unescaped `%`, escape it using `%%`'
+ end
+ end
+
+ def validate_number_of_plurals(errors, entry)
+ return unless metadata_entry&.expected_plurals
+ return unless entry.translated?
+
+ if entry.has_plural? && entry.all_translations.size != metadata_entry.expected_plurals
+ errors << "should have #{metadata_entry.expected_plurals} "\
+ "#{'translations'.pluralize(metadata_entry.expected_plurals)}"
+ end
+ end
+
+ def validate_newlines(errors, entry)
+ if entry.msgid_contains_newlines?
+ errors << 'is defined over multiple lines, this breaks some tooling.'
+ end
+
+ if entry.plural_id_contains_newlines?
+ errors << 'plural is defined over multiple lines, this breaks some tooling.'
+ end
+
+ if entry.translations_contain_newlines?
+ errors << 'has translations defined over multiple lines, this breaks some tooling.'
+ end
+ end
+
+ def validate_variables(errors, entry)
+ if entry.has_singular_translation?
+ validate_variables_in_message(errors, entry.msgid, entry.singular_translation)
+ end
+
+ if entry.has_plural?
+ entry.plural_translations.each do |translation|
+ validate_variables_in_message(errors, entry.plural_id, translation)
+ end
+ end
+ end
+
+ def validate_variables_in_message(errors, message_id, message_translation)
+ message_id = join_message(message_id)
+ required_variables = message_id.scan(VARIABLE_REGEX)
+
+ validate_unnamed_variables(errors, required_variables)
+ validate_translation(errors, message_id, required_variables)
+ validate_variable_usage(errors, message_translation, required_variables)
+ end
+
+ def validate_translation(errors, message_id, used_variables)
+ variables = fill_in_variables(used_variables)
+
+ begin
+ Gitlab::I18n.with_locale(locale) do
+ translated = if message_id.include?('|')
+ FastGettext::Translation.s_(message_id)
+ else
+ FastGettext::Translation._(message_id)
+ end
+
+ translated % variables
+ end
+
+ # `sprintf` could raise an `ArgumentError` when invalid passing something
+ # other than a Hash when using named variables
+ #
+ # `sprintf` could raise `TypeError` when passing a wrong type when using
+ # unnamed variables
+ #
+ # FastGettext::Translation could raise `RuntimeError` (raised as a string),
+ # or as subclassess `NoTextDomainConfigured` & `InvalidFormat`
+ #
+ # `FastGettext::Translation` could raise `ArgumentError` as subclassess
+ # `InvalidEncoding`, `IllegalSequence` & `InvalidCharacter`
+ rescue ArgumentError, TypeError, RuntimeError => e
+ errors << "Failure translating to #{locale} with #{variables}: #{e.message}"
+ end
+ end
+
+ def fill_in_variables(variables)
+ if variables.empty?
+ []
+ elsif variables.any? { |variable| unnamed_variable?(variable) }
+ variables.map do |variable|
+ variable == '%d' ? Random.rand(1000) : Gitlab::Utils.random_string
+ end
+ else
+ variables.inject({}) do |hash, variable|
+ variable_name = variable[/\w+/]
+ hash[variable_name] = Gitlab::Utils.random_string
+ hash
+ end
+ end
+ end
+
+ def validate_unnamed_variables(errors, variables)
+ if variables.size > 1 && variables.any? { |variable_name| unnamed_variable?(variable_name) }
+ errors << 'is combining multiple unnamed variables'
+ end
+ end
+
+ def validate_variable_usage(errors, translation, required_variables)
+ translation = join_message(translation)
+
+ # We don't need to validate when the message is empty.
+ # In this case we fall back to the default, which has all the the
+ # required variables.
+ return if translation.empty?
+
+ found_variables = translation.scan(VARIABLE_REGEX)
+
+ missing_variables = required_variables - found_variables
+ if missing_variables.any?
+ errors << "<#{translation}> is missing: [#{missing_variables.to_sentence}]"
+ end
+
+ unknown_variables = found_variables - required_variables
+ if unknown_variables.any?
+ errors << "<#{translation}> is using unknown variables: [#{unknown_variables.to_sentence}]"
+ end
+ end
+
+ def unnamed_variable?(variable_name)
+ !variable_name.start_with?('%{')
+ end
+
+ def validate_flags(errors, entry)
+ errors << "is marked #{entry.flag}" if entry.flag
+ end
+
+ def join_message(message)
+ Array(message).join
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/i18n/translation_entry.rb b/lib/gitlab/i18n/translation_entry.rb
new file mode 100644
index 00000000000..e6c95afca7e
--- /dev/null
+++ b/lib/gitlab/i18n/translation_entry.rb
@@ -0,0 +1,92 @@
+module Gitlab
+ module I18n
+ class TranslationEntry
+ PERCENT_REGEX = /(?:^|[^%])%(?!{\w*}|[a-z%])/.freeze
+
+ attr_reader :nplurals, :entry_data
+
+ def initialize(entry_data, nplurals)
+ @entry_data = entry_data
+ @nplurals = nplurals
+ end
+
+ def msgid
+ entry_data[:msgid]
+ end
+
+ def plural_id
+ entry_data[:msgid_plural]
+ end
+
+ def has_plural?
+ plural_id.present?
+ end
+
+ def singular_translation
+ all_translations.first if has_singular_translation?
+ end
+
+ def all_translations
+ @all_translations ||= entry_data.fetch_values(*translation_keys)
+ .reject(&:empty?)
+ end
+
+ def translated?
+ all_translations.any?
+ end
+
+ def plural_translations
+ return [] unless has_plural?
+ return [] unless translated?
+
+ @plural_translations ||= if has_singular_translation?
+ all_translations.drop(1)
+ else
+ all_translations
+ end
+ end
+
+ def flag
+ entry_data[:flag]
+ end
+
+ def has_singular_translation?
+ nplurals > 1 || !has_plural?
+ end
+
+ def msgid_contains_newlines?
+ msgid.is_a?(Array)
+ end
+
+ def plural_id_contains_newlines?
+ plural_id.is_a?(Array)
+ end
+
+ def translations_contain_newlines?
+ all_translations.any? { |translation| translation.is_a?(Array) }
+ end
+
+ def msgid_contains_unescaped_chars?
+ contains_unescaped_chars?(msgid)
+ end
+
+ def plural_id_contains_unescaped_chars?
+ contains_unescaped_chars?(plural_id)
+ end
+
+ def translations_contain_unescaped_chars?
+ all_translations.any? { |translation| contains_unescaped_chars?(translation) }
+ end
+
+ def contains_unescaped_chars?(string)
+ string =~ PERCENT_REGEX
+ end
+
+ private
+
+ def translation_keys
+ @translation_keys ||= entry_data.keys.select { |key| key.to_s =~ /\Amsgstr(\[\d+\])?\z/ }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/key_fingerprint.rb b/lib/gitlab/key_fingerprint.rb
deleted file mode 100644
index d9a79f7c291..00000000000
--- a/lib/gitlab/key_fingerprint.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-module Gitlab
- class KeyFingerprint
- attr_reader :key, :ssh_key
-
- # Unqualified MD5 fingerprint for compatibility
- delegate :fingerprint, to: :ssh_key, allow_nil: true
-
- def initialize(key)
- @key = key
-
- @ssh_key =
- begin
- Net::SSH::KeyFactory.load_data_public_key(key)
- rescue Net::SSH::Exception, NotImplementedError
- end
- end
-
- def valid?
- ssh_key.present?
- end
-
- def type
- return unless valid?
-
- parts = ssh_key.ssh_type.split('-')
- parts.shift if parts[0] == 'ssh'
-
- parts[0].upcase
- end
-
- def bits
- return unless valid?
-
- case type
- when 'RSA'
- ssh_key.n.num_bits
- when 'DSS', 'DSA'
- ssh_key.p.num_bits
- when 'ECDSA'
- ssh_key.group.order.num_bits
- when 'ED25519'
- 256
- else
- raise "Unsupported key type: #{type}"
- end
- end
- end
-end
diff --git a/lib/gitlab/reference_counter.rb b/lib/gitlab/reference_counter.rb
new file mode 100644
index 00000000000..bb26f1b610a
--- /dev/null
+++ b/lib/gitlab/reference_counter.rb
@@ -0,0 +1,44 @@
+module Gitlab
+ class ReferenceCounter
+ REFERENCE_EXPIRE_TIME = 600
+
+ attr_reader :gl_repository, :key
+
+ def initialize(gl_repository)
+ @gl_repository = gl_repository
+ @key = "git-receive-pack-reference-counter:#{gl_repository}"
+ end
+
+ def value
+ Gitlab::Redis::SharedState.with { |redis| (redis.get(key) || 0).to_i }
+ end
+
+ def increase
+ redis_cmd do |redis|
+ redis.incr(key)
+ redis.expire(key, REFERENCE_EXPIRE_TIME)
+ end
+ end
+
+ def decrease
+ redis_cmd do |redis|
+ current_value = redis.decr(key)
+ if current_value < 0
+ Rails.logger.warn("Reference counter for #{gl_repository} decreased" \
+ " when its value was less than 1. Reseting the counter.")
+ redis.del(key)
+ end
+ end
+ end
+
+ private
+
+ def redis_cmd
+ Gitlab::Redis::SharedState.with { |redis| yield(redis) }
+ true
+ rescue => e
+ Rails.logger.warn("GitLab: An unexpected error occurred in writing to Redis: #{e}")
+ false
+ end
+ end
+end
diff --git a/lib/gitlab/sentry.rb b/lib/gitlab/sentry.rb
index f6bdd6cf0fe..159d0e7952e 100644
--- a/lib/gitlab/sentry.rb
+++ b/lib/gitlab/sentry.rb
@@ -9,6 +9,8 @@ module Gitlab
def self.context(current_user = nil)
return unless self.enabled?
+ Raven.tags_context(locale: I18n.locale)
+
if current_user
Raven.user_context(
id: current_user.id,
diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb
new file mode 100644
index 00000000000..89ca1298120
--- /dev/null
+++ b/lib/gitlab/ssh_public_key.rb
@@ -0,0 +1,71 @@
+module Gitlab
+ class SSHPublicKey
+ Technology = Struct.new(:name, :key_class, :supported_sizes)
+
+ Technologies = [
+ Technology.new(:rsa, OpenSSL::PKey::RSA, [1024, 2048, 3072, 4096]),
+ Technology.new(:dsa, OpenSSL::PKey::DSA, [1024, 2048, 3072]),
+ Technology.new(:ecdsa, OpenSSL::PKey::EC, [256, 384, 521]),
+ Technology.new(:ed25519, Net::SSH::Authentication::ED25519::PubKey, [256])
+ ].freeze
+
+ def self.technology(name)
+ Technologies.find { |tech| tech.name.to_s == name.to_s }
+ end
+
+ def self.technology_for_key(key)
+ Technologies.find { |tech| key.is_a?(tech.key_class) }
+ end
+
+ def self.supported_sizes(name)
+ technology(name)&.supported_sizes
+ end
+
+ attr_reader :key_text, :key
+
+ # Unqualified MD5 fingerprint for compatibility
+ delegate :fingerprint, to: :key, allow_nil: true
+
+ def initialize(key_text)
+ @key_text = key_text
+
+ @key =
+ begin
+ Net::SSH::KeyFactory.load_data_public_key(key_text)
+ rescue StandardError, NotImplementedError
+ end
+ end
+
+ def valid?
+ key.present?
+ end
+
+ def type
+ technology.name if valid?
+ end
+
+ def bits
+ return unless valid?
+
+ case type
+ when :rsa
+ key.n.num_bits
+ when :dsa
+ key.p.num_bits
+ when :ecdsa
+ key.group.order.num_bits
+ when :ed25519
+ 256
+ else
+ raise "Unsupported key type: #{type}"
+ end
+ end
+
+ private
+
+ def technology
+ @technology ||=
+ self.class.technology_for_key(key) || raise("Unsupported key type: #{key.class}")
+ end
+ end
+end
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index 9670c93759e..abb3d3a02c3 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -42,5 +42,9 @@ module Gitlab
'No'
end
end
+
+ def random_string
+ Random.rand(Float::MAX.to_i).to_s(36)
+ end
end
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index a362a3a0bc6..e5ad9b5a40c 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -35,10 +35,7 @@ module Gitlab
when 'git_receive_pack'
Gitlab::GitalyClient.feature_enabled?(:post_receive_pack)
when 'git_upload_pack'
- Gitlab::GitalyClient.feature_enabled?(
- :post_upload_pack,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT
- )
+ true
when 'info_refs'
true
else
diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake
index b48e4dce445..e1491f29b5e 100644
--- a/lib/tasks/gettext.rake
+++ b/lib/tasks/gettext.rake
@@ -19,4 +19,44 @@ namespace :gettext do
Rake::Task['gettext:pack'].invoke
Rake::Task['gettext:po_to_json'].invoke
end
+
+ desc 'Lint all po files in `locale/'
+ task lint: :environment do
+ FastGettext.silence_errors
+ files = Dir.glob(Rails.root.join('locale/*/gitlab.po'))
+
+ linters = files.map do |file|
+ locale = File.basename(File.dirname(file))
+
+ Gitlab::I18n::PoLinter.new(file, locale)
+ end
+
+ pot_file = Rails.root.join('locale/gitlab.pot')
+ linters.unshift(Gitlab::I18n::PoLinter.new(pot_file))
+
+ failed_linters = linters.select { |linter| linter.errors.any? }
+
+ if failed_linters.empty?
+ puts 'All PO files are valid.'
+ else
+ failed_linters.each do |linter|
+ report_errors_for_file(linter.po_path, linter.errors)
+ end
+
+ raise "Not all PO-files are valid: #{failed_linters.map(&:po_path).to_sentence}"
+ end
+ end
+
+ def report_errors_for_file(file, errors_for_file)
+ puts "Errors in `#{file}`:"
+
+ errors_for_file.each do |message_id, errors|
+ puts " #{message_id}"
+ errors.each do |error|
+ spaces = ' ' * 4
+ error = error.lines.join("#{spaces}")
+ puts "#{spaces}#{error}"
+ end
+ end
+ end
end