431 lines
14 KiB
Diff
431 lines
14 KiB
Diff
--- a/app/models/namespace.rb
|
|
+++ b/app/models/namespace.rb
|
|
@@ -111,6 +111,8 @@
|
|
|
|
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
|
|
|
|
+ remove_exports!
|
|
+
|
|
# If repositories moved successfully we need to
|
|
# send update instructions to users.
|
|
# However we cannot allow rollback since we moved namespace dir
|
|
@@ -174,5 +176,15 @@
|
|
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
|
|
end
|
|
end
|
|
+
|
|
+ remove_exports!
|
|
+ end
|
|
+
|
|
+ def remove_exports!
|
|
+ Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
|
|
+ end
|
|
+
|
|
+ def export_path
|
|
+ File.join(Gitlab::ImportExport.storage_path, path_was)
|
|
end
|
|
end
|
|
--- a/lib/api/deploy_keys.rb
|
|
+++ b/lib/api/deploy_keys.rb
|
|
@@ -100,15 +100,19 @@
|
|
present key.deploy_key, with: Entities::SSHKey
|
|
end
|
|
|
|
- desc 'Delete existing deploy key of currently authenticated user' do
|
|
+ desc 'Delete deploy key for a project' do
|
|
success Key
|
|
end
|
|
params do
|
|
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
|
|
end
|
|
delete ":id/#{path}/:key_id" do
|
|
- key = user_project.deploy_keys.find(params[:key_id])
|
|
- key.destroy
|
|
+ key = user_project.deploy_keys_projects.find_by(deploy_key_id: params[:key_id])
|
|
+ if key
|
|
+ key.destroy
|
|
+ else
|
|
+ not_found!('Deploy Key')
|
|
+ end
|
|
end
|
|
end
|
|
end
|
|
--- a/lib/api/helpers.rb
|
|
+++ b/lib/api/helpers.rb
|
|
@@ -97,6 +97,12 @@
|
|
IssuesFinder.new(current_user, project_id: user_project.id).find(id)
|
|
end
|
|
|
|
+ def find_merge_request_with_access(id, access_level = :read_merge_request)
|
|
+ merge_request = user_project.merge_requests.find(id)
|
|
+ authorize! access_level, merge_request
|
|
+ merge_request
|
|
+ end
|
|
+
|
|
def paginate(relation)
|
|
relation.page(params[:page]).per(params[:per_page].to_i).tap do |data|
|
|
add_pagination_headers(data)
|
|
--- a/lib/api/merge_request_diffs.rb
|
|
+++ b/lib/api/merge_request_diffs.rb
|
|
@@ -15,10 +15,8 @@
|
|
end
|
|
|
|
get ":id/merge_requests/:merge_request_id/versions" do
|
|
- merge_request = user_project.merge_requests.
|
|
- find(params[:merge_request_id])
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
|
|
- authorize! :read_merge_request, merge_request
|
|
present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff
|
|
end
|
|
|
|
@@ -34,10 +32,8 @@
|
|
end
|
|
|
|
get ":id/merge_requests/:merge_request_id/versions/:version_id" do
|
|
- merge_request = user_project.merge_requests.
|
|
- find(params[:merge_request_id])
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
|
|
- authorize! :read_merge_request, merge_request
|
|
present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull
|
|
end
|
|
end
|
|
--- a/lib/api/merge_requests.rb
|
|
+++ b/lib/api/merge_requests.rb
|
|
@@ -121,9 +121,7 @@
|
|
# GET /projects/:id/merge_requests/:merge_request_id
|
|
#
|
|
get path do
|
|
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
|
|
-
|
|
- authorize! :read_merge_request, merge_request
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
|
|
present merge_request, with: Entities::MergeRequest, current_user: current_user
|
|
end
|
|
@@ -138,9 +136,8 @@
|
|
# GET /projects/:id/merge_requests/:merge_request_id/commits
|
|
#
|
|
get "#{path}/commits" do
|
|
- merge_request = user_project.merge_requests.
|
|
- find(params[:merge_request_id])
|
|
- authorize! :read_merge_request, merge_request
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
+
|
|
present merge_request.commits, with: Entities::RepoCommit
|
|
end
|
|
|
|
@@ -154,9 +151,8 @@
|
|
# GET /projects/:id/merge_requests/:merge_request_id/changes
|
|
#
|
|
get "#{path}/changes" do
|
|
- merge_request = user_project.merge_requests.
|
|
- find(params[:merge_request_id])
|
|
- authorize! :read_merge_request, merge_request
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
+
|
|
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user
|
|
end
|
|
|
|
@@ -174,8 +170,7 @@
|
|
optional :milestone_id, type: Integer, desc: 'The ID of the new milestone'
|
|
end
|
|
put path do
|
|
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
|
|
- authorize! :update_merge_request, merge_request
|
|
+ merge_request = find_merge_request_with_access(params.delete(:merge_request_id), :update_merge_request)
|
|
|
|
# Ensure source_branch is not specified
|
|
if params[:source_branch].present?
|
|
@@ -262,10 +257,7 @@
|
|
# GET /projects/:id/merge_requests/:merge_request_id/comments
|
|
#
|
|
get "#{path}/comments" do
|
|
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
|
|
-
|
|
- authorize! :read_merge_request, merge_request
|
|
-
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
present paginate(merge_request.notes.fresh), with: Entities::MRNote
|
|
end
|
|
|
|
@@ -284,9 +276,7 @@
|
|
post "#{path}/comments" do
|
|
required_attributes! [:note]
|
|
|
|
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
|
|
-
|
|
- authorize! :create_note, merge_request
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id], :create_note)
|
|
|
|
opts = {
|
|
note: params[:note],
|
|
@@ -311,7 +301,7 @@
|
|
# Examples:
|
|
# GET /projects/:id/merge_requests/:merge_request_id/closes_issues
|
|
get "#{path}/closes_issues" do
|
|
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
|
|
+ merge_request = find_merge_request_with_access(params[:merge_request_id])
|
|
issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
|
|
present paginate(issues), with: issue_entity(user_project), current_user: current_user
|
|
end
|
|
--- a/lib/api/notes.rb
|
|
+++ b/lib/api/notes.rb
|
|
@@ -74,21 +74,27 @@
|
|
required_attributes! [:body]
|
|
|
|
opts = {
|
|
- note: params[:body],
|
|
- noteable_type: noteables_str.classify,
|
|
- noteable_id: params[noteable_id_str]
|
|
+ note: params[:body],
|
|
+ noteable_type: noteables_str.classify,
|
|
+ noteable_id: params[noteable_id_str]
|
|
}
|
|
|
|
- if params[:created_at] && (current_user.is_admin? || user_project.owner == current_user)
|
|
- opts[:created_at] = params[:created_at]
|
|
- end
|
|
+ noteable = user_project.send(noteables_str.to_sym).find(opts[:noteable_id])
|
|
+
|
|
+ if can?(current_user, noteable_read_ability_name(noteable), noteable)
|
|
+ if params[:created_at] && (current_user.is_admin? || user_project.owner == current_user)
|
|
+ opts[:created_at] = params[:created_at]
|
|
+ end
|
|
|
|
- note = ::Notes::CreateService.new(user_project, current_user, opts).execute
|
|
+ note = ::Notes::CreateService.new(user_project, current_user, opts).execute
|
|
|
|
- if note.valid?
|
|
- present note, with: Entities::const_get(note.class.name)
|
|
+ if note.valid?
|
|
+ present note, with: Entities::const_get(note.class.name)
|
|
+ else
|
|
+ not_found!("Note #{note.errors.messages}")
|
|
+ end
|
|
else
|
|
- not_found!("Note #{note.errors.messages}")
|
|
+ not_found!("Note")
|
|
end
|
|
end
|
|
|
|
--- a/lib/api/subscriptions.rb
|
|
+++ b/lib/api/subscriptions.rb
|
|
@@ -3,8 +3,8 @@
|
|
before { authenticate! }
|
|
|
|
subscribable_types = {
|
|
- 'merge_request' => proc { |id| user_project.merge_requests.find(id) },
|
|
- 'merge_requests' => proc { |id| user_project.merge_requests.find(id) },
|
|
+ 'merge_request' => proc { |id| find_merge_request_with_access(id, :update_merge_request) },
|
|
+ 'merge_requests' => proc { |id| find_merge_request_with_access(id, :update_merge_request) },
|
|
'issues' => proc { |id| find_project_issue(id) },
|
|
'labels' => proc { |id| find_project_label(id) },
|
|
}
|
|
--- a/lib/api/todos.rb
|
|
+++ b/lib/api/todos.rb
|
|
@@ -4,7 +4,7 @@
|
|
before { authenticate! }
|
|
|
|
ISSUABLE_TYPES = {
|
|
- 'merge_requests' => ->(id) { user_project.merge_requests.find(id) },
|
|
+ 'merge_requests' => ->(id) { find_merge_request_with_access(id) },
|
|
'issues' => ->(id) { find_project_issue(id) }
|
|
}
|
|
|
|
--- /dev/null
|
|
+++ b/spec/features/projects/import_export/namespace_export_file_spec.rb
|
|
@@ -0,0 +1,62 @@
|
|
+require 'spec_helper'
|
|
+
|
|
+feature 'Import/Export - Namespace export file cleanup', feature: true, js: true do
|
|
+ let(:export_path) { "#{Dir::tmpdir}/import_file_spec" }
|
|
+ let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys }
|
|
+
|
|
+ let(:project) { create(:empty_project) }
|
|
+
|
|
+ background do
|
|
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
|
|
+ end
|
|
+
|
|
+ after do
|
|
+ FileUtils.rm_rf(export_path, secure: true)
|
|
+ end
|
|
+
|
|
+ context 'admin user' do
|
|
+ before do
|
|
+ login_as(:admin)
|
|
+ end
|
|
+
|
|
+ context 'moving the namespace' do
|
|
+ scenario 'removes the export file' do
|
|
+ setup_export_project
|
|
+
|
|
+ old_export_path = project.export_path.dup
|
|
+
|
|
+ expect(File).to exist(old_export_path)
|
|
+
|
|
+ project.namespace.update(path: 'new_path')
|
|
+
|
|
+ expect(File).not_to exist(old_export_path)
|
|
+ end
|
|
+ end
|
|
+
|
|
+ context 'deleting the namespace' do
|
|
+ scenario 'removes the export file' do
|
|
+ setup_export_project
|
|
+
|
|
+ old_export_path = project.export_path.dup
|
|
+
|
|
+ expect(File).to exist(old_export_path)
|
|
+
|
|
+ project.namespace.destroy
|
|
+
|
|
+ expect(File).not_to exist(old_export_path)
|
|
+ end
|
|
+ end
|
|
+
|
|
+ def setup_export_project
|
|
+ visit edit_namespace_project_path(project.namespace, project)
|
|
+
|
|
+ expect(page).to have_content('Export project')
|
|
+
|
|
+ click_link 'Export project'
|
|
+
|
|
+ visit edit_namespace_project_path(project.namespace, project)
|
|
+
|
|
+ expect(page).to have_content('Download export')
|
|
+ end
|
|
+ end
|
|
+end
|
|
--- a/spec/models/namespace_spec.rb
|
|
+++ b/spec/models/namespace_spec.rb
|
|
@@ -69,6 +69,7 @@
|
|
new_path = @namespace.path + "_new"
|
|
allow(@namespace).to receive(:path_was).and_return(@namespace.path)
|
|
allow(@namespace).to receive(:path).and_return(new_path)
|
|
+ expect(@namespace).to receive(:remove_exports!)
|
|
expect(@namespace.move_dir).to be_truthy
|
|
end
|
|
|
|
@@ -91,11 +92,17 @@
|
|
let!(:project) { create(:project, namespace: namespace) }
|
|
let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) }
|
|
|
|
- before { namespace.destroy }
|
|
-
|
|
it "removes its dirs when deleted" do
|
|
+ namespace.destroy
|
|
+
|
|
expect(File.exist?(path)).to be(false)
|
|
end
|
|
+
|
|
+ it 'removes the exports folder' do
|
|
+ expect(namespace).to receive(:remove_exports!)
|
|
+
|
|
+ namespace.destroy
|
|
+ end
|
|
end
|
|
|
|
describe '.find_by_path_or_name' do
|
|
--- a/spec/requests/api/merge_requests_spec.rb
|
|
+++ b/spec/requests/api/merge_requests_spec.rb
|
|
@@ -597,6 +597,15 @@
|
|
expect(json_response.first['title']).to eq(issue.title)
|
|
expect(json_response.first['id']).to eq(issue.id)
|
|
end
|
|
+
|
|
+ it 'returns 403 if the user has no access to the merge request' do
|
|
+ guest = create(:user)
|
|
+ project.team << [guest, :guest]
|
|
+
|
|
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", guest)
|
|
+
|
|
+ expect(response).to have_http_status(403)
|
|
+ end
|
|
end
|
|
|
|
describe 'POST :id/merge_requests/:merge_request_id/subscription' do
|
|
@@ -618,6 +627,15 @@
|
|
|
|
expect(response).to have_http_status(404)
|
|
end
|
|
+
|
|
+ it 'returns 403 if user has no access to read code' do
|
|
+ guest = create(:user)
|
|
+ project.team << [guest, :guest]
|
|
+
|
|
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest)
|
|
+
|
|
+ expect(response).to have_http_status(403)
|
|
+ end
|
|
end
|
|
|
|
describe 'DELETE :id/merge_requests/:merge_request_id/subscription' do
|
|
@@ -639,6 +657,15 @@
|
|
|
|
expect(response).to have_http_status(404)
|
|
end
|
|
+
|
|
+ it 'returns 403 if user has no access to read code' do
|
|
+ guest = create(:user)
|
|
+ project.team << [guest, :guest]
|
|
+
|
|
+ delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest)
|
|
+
|
|
+ expect(response).to have_http_status(403)
|
|
+ end
|
|
end
|
|
|
|
def mr_with_later_created_and_updated_at_time
|
|
--- a/spec/requests/api/notes_spec.rb
|
|
+++ b/spec/requests/api/notes_spec.rb
|
|
@@ -253,6 +253,18 @@
|
|
end
|
|
end
|
|
|
|
+ context 'when user does not have access to read the noteable' do
|
|
+ it 'responds with 404' do
|
|
+ project = create(:empty_project, :private) { |p| p.team << [user, :guest] }
|
|
+ issue = create(:issue, :confidential, project: project)
|
|
+
|
|
+ post api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
|
|
+ body: 'Foo'
|
|
+
|
|
+ expect(response).to have_http_status(404)
|
|
+ end
|
|
+ end
|
|
+
|
|
context 'when user does not have access to create noteable' do
|
|
let(:private_issue) { create(:issue, project: create(:project, :private)) }
|
|
|
|
--- a/spec/requests/api/todos_spec.rb
|
|
+++ b/spec/requests/api/todos_spec.rb
|
|
@@ -183,12 +183,25 @@
|
|
|
|
expect(response.status).to eq(404)
|
|
end
|
|
+
|
|
+ it 'returns an error if the issuable is not accessible' do
|
|
+ guest = create(:user)
|
|
+ project_1.team << [guest, :guest]
|
|
+
|
|
+ post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", guest)
|
|
+
|
|
+ if issuable_type == 'merge_requests'
|
|
+ expect(response).to have_http_status(403)
|
|
+ else
|
|
+ expect(response).to have_http_status(404)
|
|
+ end
|
|
+ end
|
|
end
|
|
|
|
describe 'POST :id/issuable_type/:issueable_id/todo' do
|
|
context 'for an issue' do
|
|
it_behaves_like 'an issuable', 'issues' do
|
|
- let(:issuable) { create(:issue, author: author_1, project: project_1) }
|
|
+ let(:issuable) { create(:issue, :confidential, author: author_1, project: project_1) }
|
|
end
|
|
end
|
|
|