BigW Consortium Gitlab

Commit 32b2ff26 by Tiago Botelho

Adds remote messsage when project is created in a push over SSH or HTTP

parent 35882e68
...@@ -11,10 +11,14 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -11,10 +11,14 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def info_refs def info_refs
log_user_activity if upload_pack? log_user_activity if upload_pack?
if project.blank? && params[:service] == 'git-receive-pack' if user && project.blank? && receive_pack?
@project = ::Projects::CreateService.new(user, project_params).execute @project = ::Projects::CreateService.new(user, project_params).execute
return render_ok if @project.saved? if @project.saved?
Gitlab::Checks::NewProject.new(user, @project, 'http').add_new_project_message
else
raise Gitlab::GitAccess::NotFoundError, 'Could not create project'
end
end end
render_ok render_ok
...@@ -32,15 +36,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -32,15 +36,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController
private private
def project_params
{
description: "",
path: params[:project_id].gsub("\.git", ''),
namespace_id: namespace.id.to_s,
visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s
}
end
def download_request? def download_request?
upload_pack? upload_pack?
end end
...@@ -49,6 +44,10 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -49,6 +44,10 @@ class Projects::GitHttpController < Projects::GitHttpClientController
git_command == 'git-upload-pack' git_command == 'git-upload-pack'
end end
def receive_pack?
git_command == 'git-receive-pack'
end
def git_command def git_command
if action_name == 'info_refs' if action_name == 'info_refs'
params[:service] params[:service]
...@@ -74,10 +73,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -74,10 +73,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController
@access ||= access_klass.new(access_actor, project, 'http', authentication_abilities: authentication_abilities, redirected_path: redirected_path, target_namespace: namespace) @access ||= access_klass.new(access_actor, project, 'http', authentication_abilities: authentication_abilities, redirected_path: redirected_path, target_namespace: namespace)
end end
def namespace
@namespace = Namespace.find_by_path_or_name(params[:namespace_id])
end
def access_actor def access_actor
return user if user return user if user
return :ci if ci? return :ci if ci?
...@@ -93,6 +88,19 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -93,6 +88,19 @@ class Projects::GitHttpController < Projects::GitHttpClientController
@access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess @access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
end end
def project_params
{
description: "",
path: Project.parse_project_id(params[:project_id]),
namespace_id: namespace&.id,
visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s
}
end
def namespace
@namespace ||= Namespace.find_by_path_or_name(params[:namespace_id])
end
def log_user_activity def log_user_activity
Users::ActivityService.new(user, 'pull').execute Users::ActivityService.new(user, 'pull').execute
end end
......
...@@ -468,6 +468,10 @@ class Project < ActiveRecord::Base ...@@ -468,6 +468,10 @@ class Project < ActiveRecord::Base
def group_ids def group_ids
joins(:namespace).where(namespaces: { type: 'Group' }).select(:namespace_id) joins(:namespace).where(namespaces: { type: 'Group' }).select(:namespace_id)
end end
def parse_project_id(project_id)
project_id.gsub("\.git", '')
end
end end
# returns all ancestor-groups upto but excluding the given namespace # returns all ancestor-groups upto but excluding the given namespace
......
...@@ -29,6 +29,10 @@ module API ...@@ -29,6 +29,10 @@ module API
{} {}
end end
def receive_pack?
params[:action] == 'git-receive-pack'
end
def fix_git_env_repository_paths(env, repository_path) def fix_git_env_repository_paths(env, repository_path)
if obj_dir_relative = env['GIT_OBJECT_DIRECTORY_RELATIVE'].presence if obj_dir_relative = env['GIT_OBJECT_DIRECTORY_RELATIVE'].presence
env['GIT_OBJECT_DIRECTORY'] = File.join(repository_path, obj_dir_relative) env['GIT_OBJECT_DIRECTORY'] = File.join(repository_path, obj_dir_relative)
...@@ -62,6 +66,18 @@ module API ...@@ -62,6 +66,18 @@ module API
private private
def project_path_regex
@project_regex ||= /\A(?<namespace_id>#{Gitlab::PathRegex.full_namespace_route_regex})\/(?<project_id>#{Gitlab::PathRegex.project_git_route_regex})\z/.freeze
end
def project_match
@match ||= params[:project].match(project_path_regex).captures
end
def namespace
@namespace ||= Namespace.find_by_path_or_name(project_match[:namespace_id])
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables # rubocop:disable Gitlab/ModuleWithInstanceVariables
def set_project def set_project
if params[:gl_repository] if params[:gl_repository]
......
...@@ -43,7 +43,7 @@ module API ...@@ -43,7 +43,7 @@ module API
access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
access_checker = access_checker_klass access_checker = access_checker_klass
.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities, redirected_path: redirected_path, target_namespace: user.namespace) .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities, redirected_path: redirected_path, target_namespace: namespace)
begin begin
access_checker.check(params[:action], params[:changes]) access_checker.check(params[:action], params[:changes])
...@@ -51,17 +51,21 @@ module API ...@@ -51,17 +51,21 @@ module API
return { status: false, message: e.message } return { status: false, message: e.message }
end end
if project.blank? && params[:action] == 'git-receive-pack' if user && project.blank? && receive_pack?
project_params = { project_params = {
description: "", description: "",
path: params[:project].split('/').last.gsub("\.git", ''), path: Project.parse_project_id(project_match[:project_name]),
namespace_id: user.namespace.id.to_s, namespace_id: namespace&.id,
visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s
} }
@project = ::Projects::CreateService.new(user, project_params).execute @project = ::Projects::CreateService.new(user, project_params).execute
return { status: false, message: "Could not create project" } unless @project.saved? if @project.saved?
Gitlab::Checks::NewProject.new(user, @project, protocol).add_new_project_message
else
return { status: false, message: "Could not create project" }
end
end end
log_user_activity(actor) log_user_activity(actor)
...@@ -221,7 +225,10 @@ module API ...@@ -221,7 +225,10 @@ module API
# key could be used # key could be used
if user if user
redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id) redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id)
new_project_message = Gitlab::Checks::NewProject.fetch_new_project_message(user.id, project.id)
output[:redirected_message] = redirect_message if redirect_message output[:redirected_message] = redirect_message if redirect_message
output[:new_project_message] = new_project_message if new_project_message
end end
output output
......
module Gitlab
module Checks
class NewProject
NEW_PROJECT = "new_project".freeze
def initialize(user, project, protocol)
@user = user
@project = project
@protocol = protocol
end
def self.fetch_new_project_message(user_id, project_id)
new_project_key = new_project_message_key(user_id, project_id)
Gitlab::Redis::SharedState.with do |redis|
message = redis.get(new_project_key)
redis.del(new_project_key)
message
end
end
def add_new_project_message
Gitlab::Redis::SharedState.with do |redis|
key = self.class.new_project_message_key(user.id, project.id)
redis.setex(key, 5.minutes, new_project_message)
end
end
def new_project_message
<<~MESSAGE.strip_heredoc
The private project #{project.full_path} was created.
To configure the remote, run:
git remote add origin #{git_url}
To view the project, visit:
#{project_url}
MESSAGE
end
private
attr_reader :project, :user, :protocol
def self.new_project_message_key(user_id, project_id)
"#{NEW_PROJECT}:#{user_id}:#{project_id}"
end
def project_url
Gitlab::Routing.url_helpers.project_url(project)
end
def git_url
protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo
end
end
end
end
...@@ -13,6 +13,7 @@ module Gitlab ...@@ -13,6 +13,7 @@ module Gitlab
'This deploy key does not have write access to this project.', 'This deploy key does not have write access to this project.',
no_repo: 'A repository for this project does not exist yet.', no_repo: 'A repository for this project does not exist yet.',
project_not_found: 'The project you were looking for could not be found.', project_not_found: 'The project you were looking for could not be found.',
namespace_not_found: 'The namespace you were looking for could not be found.',
account_blocked: 'Your account has been blocked.', account_blocked: 'Your account has been blocked.',
command_not_allowed: "The command you're trying to execute is not allowed.", command_not_allowed: "The command you're trying to execute is not allowed.",
upload_pack_disabled_over_http: 'Pulling over HTTP is not allowed.', upload_pack_disabled_over_http: 'Pulling over HTTP is not allowed.',
...@@ -41,18 +42,18 @@ module Gitlab ...@@ -41,18 +42,18 @@ module Gitlab
check_protocol! check_protocol!
check_valid_actor! check_valid_actor!
check_active_user! check_active_user!
check_project_accessibility! check_project_accessibility!(cmd)
check_project_moved! check_project_moved!
check_command_disabled!(cmd) check_command_disabled!(cmd)
check_command_existence!(cmd) check_command_existence!(cmd)
check_repository_existence! check_repository_existence!(cmd)
check_repository_creation!
case cmd case cmd
when *DOWNLOAD_COMMANDS when *DOWNLOAD_COMMANDS
check_download_access! check_download_access!
when *PUSH_COMMANDS when *PUSH_COMMANDS
check_push_access!(changes) check_push_access!(cmd, changes)
check_repository_creation!(cmd)
end end
true true
...@@ -98,8 +99,8 @@ module Gitlab ...@@ -98,8 +99,8 @@ module Gitlab
end end
end end
def check_project_accessibility! def check_project_accessibility!(cmd)
if (project.blank? || !can_read_project?) && !can_create_project_in_namespace? if (project.blank? || !can_read_project?) && !can_create_project_in_namespace?(cmd)
raise NotFoundError, ERROR_MESSAGES[:project_not_found] raise NotFoundError, ERROR_MESSAGES[:project_not_found]
end end
end end
...@@ -142,16 +143,20 @@ module Gitlab ...@@ -142,16 +143,20 @@ module Gitlab
end end
end end
def check_repository_existence! def check_repository_existence!(cmd)
if (project.blank? || !project.repository.exists?) && !can_create_project_in_namespace? if (project.blank? || !project.repository.exists?) && !can_create_project_in_namespace?(cmd)
raise UnauthorizedError, ERROR_MESSAGES[:no_repo] raise UnauthorizedError, ERROR_MESSAGES[:no_repo]
end end
end end
def check_repository_creation! def check_repository_creation!(cmd)
return unless target_namespace return unless project.blank?
unless can_create_project_in_namespace? unless target_namespace
raise NotFoundError, ERROR_MESSAGES[:namespace_not_found]
end
unless can_create_project_in_namespace?(cmd)
raise UnauthorizedError, ERROR_MESSAGES[:create] raise UnauthorizedError, ERROR_MESSAGES[:create]
end end
end end
...@@ -168,8 +173,8 @@ module Gitlab ...@@ -168,8 +173,8 @@ module Gitlab
end end
end end
def check_push_access!(changes) def check_push_access!(cmd, changes)
return if can_create_project_in_namespace? return if project.blank? && can_create_project_in_namespace?(cmd)
if project.repository_read_only? if project.repository_read_only?
raise UnauthorizedError, ERROR_MESSAGES[:read_only] raise UnauthorizedError, ERROR_MESSAGES[:read_only]
...@@ -247,8 +252,8 @@ module Gitlab ...@@ -247,8 +252,8 @@ module Gitlab
end || Guest.can?(:read_project, project) end || Guest.can?(:read_project, project)
end end
def can_create_project_in_namespace? def can_create_project_in_namespace?(cmd)
return unless target_namespace return false unless PUSH_COMMANDS.include?(cmd) && target_namespace
user.can?(:create_projects, target_namespace) user.can?(:create_projects, target_namespace)
end end
......
...@@ -25,6 +25,10 @@ module Gitlab ...@@ -25,6 +25,10 @@ module Gitlab
true true
end end
def check_repository_creation!(cmd)
# Method not used in wiki
end
def push_to_read_only_message def push_to_read_only_message
ERROR_MESSAGES[:read_only] ERROR_MESSAGES[:read_only]
end end
......
...@@ -501,8 +501,9 @@ describe Gitlab::GitAccess do ...@@ -501,8 +501,9 @@ describe Gitlab::GitAccess do
end end
aggregate_failures do aggregate_failures do
Gitlab::GitAccess::ALL_COMMANDS.each do |cmd|
matrix.each do |action, allowed| matrix.each do |action, allowed|
check = -> { access.send(:check_push_access!, changes[action]) } check = -> { access.send(:check_push_access!, cmd, changes[action]) }
if allowed if allowed
expect(&check).not_to raise_error, expect(&check).not_to raise_error,
...@@ -516,6 +517,7 @@ describe Gitlab::GitAccess do ...@@ -516,6 +517,7 @@ describe Gitlab::GitAccess do
end end
end end
end end
end
permissions_matrix = { permissions_matrix = {
admin: { admin: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment