Commit ec81ecae authored by Markus Koller's avatar Markus Koller Committed by Mark Chao

Refactor Git/LFS request specs into shared examples

This allows us to reuse them in EE.

- The shared examples for `Repositories::GitHttpController` were moved
  without any changes.

- The LFS request specs were cleaned up and simplified a bit.
parent c69f85f2
...@@ -9,120 +9,6 @@ RSpec.describe Repositories::GitHttpController do ...@@ -9,120 +9,6 @@ RSpec.describe Repositories::GitHttpController do
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) } let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) }
let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) } let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) }
shared_examples Repositories::GitHttpController do
let(:repository_path) { "#{container.full_path}.git" }
let(:params) { { repository_path: repository_path } }
describe 'HEAD #info_refs' do
it 'returns 403' do
head :info_refs, params: params
expect(response).to have_gitlab_http_status(:forbidden)
end
end
describe 'GET #info_refs' do
let(:params) { super().merge(service: 'git-upload-pack') }
it 'returns 401 for unauthenticated requests to public repositories when http protocol is disabled' do
stub_application_setting(enabled_git_access_protocol: 'ssh')
allow(controller).to receive(:basic_auth_provided?).and_call_original
expect(controller).to receive(:http_download_allowed?).and_call_original
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'calls the right access checker class with the right object' do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
access_double = double
options = {
authentication_abilities: [:download_code],
repository_path: repository_path,
redirected_path: nil,
auth_result_type: :none
}
expect(access_checker_class).to receive(:new)
.with(nil, container, 'http', hash_including(options))
.and_return(access_double)
allow(access_double).to receive(:check).and_return(false)
get :info_refs, params: params
end
context 'with authorized user' do
before do
request.headers.merge! auth_env(user.username, user.password, nil)
end
it 'returns 200' do
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:ok)
end
it 'updates the user activity' do
expect_next_instance_of(Users::ActivityService) do |activity_service|
expect(activity_service).to receive(:execute)
end
get :info_refs, params: params
end
include_context 'parsed logs' do
it 'adds user info to the logs' do
get :info_refs, params: params
expect(log_data).to include('username' => user.username,
'user_id' => user.id,
'meta.user' => user.username)
end
end
end
context 'with exceptions' do
before do
allow(controller).to receive(:authenticate_user).and_return(true)
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
end
it 'returns 503 with GRPC Unavailable' do
allow(controller).to receive(:access_check).and_raise(GRPC::Unavailable)
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:service_unavailable)
end
it 'returns 503 with timeout error' do
allow(controller).to receive(:access_check).and_raise(Gitlab::GitAccess::TimeoutError)
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:service_unavailable)
expect(response.body).to eq 'Gitlab::GitAccess::TimeoutError'
end
end
end
describe 'POST #git_upload_pack' do
before do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
end
it 'returns 200' do
post :git_upload_pack, params: params
expect(response).to have_gitlab_http_status(:ok)
end
end
end
context 'when repository container is a project' do context 'when repository container is a project' do
it_behaves_like Repositories::GitHttpController do it_behaves_like Repositories::GitHttpController do
let(:container) { project } let(:container) { project }
......
...@@ -6,42 +6,23 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -6,42 +6,23 @@ RSpec.describe 'Git LFS API and storage' do
include ProjectForksHelper include ProjectForksHelper
include WorkhorseHelpers include WorkhorseHelpers
let_it_be(:project, reload: true) { create(:project, :repository) } let_it_be(:project, reload: true) { create(:project, :empty_repo) }
let_it_be(:other_project) { create(:project, :repository) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:lfs_object) { create(:lfs_object, :with_file) }
let(:headers) do context 'with projects' do
{ it_behaves_like 'LFS http requests' do
'Authorization' => authorization, let_it_be(:other_project, reload: true) { create(:project, :empty_repo) }
'X-Sendfile-Type' => 'X-Sendfile'
}.compact
end
let(:include_workhorse_jwt_header) { true }
let(:authorization) { }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:sample_oid) { lfs_object.oid }
let(:sample_size) { lfs_object.size }
let(:sample_object) { { 'oid' => sample_oid, 'size' => sample_size } }
let(:non_existing_object_oid) { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
let(:non_existing_object_size) { 1575078 }
let(:non_existing_object) { { 'oid' => non_existing_object_oid, 'size' => non_existing_object_size } }
let(:multiple_objects) { [sample_object, non_existing_object] }
let(:lfs_enabled) { true }
before do let(:container) { project }
stub_lfs_setting(enabled: lfs_enabled) let(:authorize_guest) { project.add_guest(user) }
end let(:authorize_download) { project.add_reporter(user) }
let(:authorize_upload) { project.add_developer(user) }
context 'project specific LFS settings' do context 'project specific LFS settings' do
let(:body) { upload_body(sample_object) } let(:body) { upload_body(sample_object) }
let(:authorization) { authorize_user }
before do before do
project.add_maintainer(user) authorize_upload
project.update_attribute(:lfs_enabled, project_lfs_enabled) project.update_attribute(:lfs_enabled, project_lfs_enabled)
subject subject
...@@ -51,13 +32,13 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -51,13 +32,13 @@ RSpec.describe 'Git LFS API and storage' do
let(:project_lfs_enabled) { false } let(:project_lfs_enabled) { false }
context 'when uploading' do context 'when uploading' do
subject { post_lfs_json(batch_url(project), body, headers) } subject(:request) { post_lfs_json(batch_url(project), body, headers) }
it_behaves_like 'LFS http 404 response' it_behaves_like 'LFS http 404 response'
end end
context 'when downloading' do context 'when downloading' do
subject { get(objects_url(project, sample_oid), params: {}, headers: headers) } subject(:request) { get(objects_url(project, sample_oid), params: {}, headers: headers) }
it_behaves_like 'LFS http 404 response' it_behaves_like 'LFS http 404 response'
end end
...@@ -67,13 +48,13 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -67,13 +48,13 @@ RSpec.describe 'Git LFS API and storage' do
let(:project_lfs_enabled) { true } let(:project_lfs_enabled) { true }
context 'when uploading' do context 'when uploading' do
subject { post_lfs_json(batch_url(project), body, headers) } subject(:request) { post_lfs_json(batch_url(project), body, headers) }
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
end end
context 'when downloading' do context 'when downloading' do
subject { get(objects_url(project, sample_oid), params: {}, headers: headers) } subject(:request) { get(objects_url(project, sample_oid), params: {}, headers: headers) }
it_behaves_like 'LFS http 200 blob response' it_behaves_like 'LFS http 200 blob response'
end end
...@@ -81,26 +62,21 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -81,26 +62,21 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'when fetching LFS object' do describe 'when fetching LFS object' do
let(:update_permissions) { } subject(:request) { get objects_url(project, sample_oid), params: {}, headers: headers }
let(:before_get) { }
let(:response) { request && super() }
before do before do
project.lfs_objects << lfs_object project.lfs_objects << lfs_object
update_permissions
before_get
get objects_url(project, sample_oid), params: {}, headers: headers
end end
context 'when LFS uses object storage' do context 'when LFS uses object storage' do
let(:authorization) { authorize_user } before do
authorize_download
let(:update_permissions) do
project.add_maintainer(user)
end end
context 'when proxy download is enabled' do context 'when proxy download is enabled' do
let(:before_get) do before do
stub_lfs_object_storage(proxy_download: true) stub_lfs_object_storage(proxy_download: true)
lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE) lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE)
end end
...@@ -112,7 +88,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -112,7 +88,7 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when proxy download is disabled' do context 'when proxy download is disabled' do
let(:before_get) do before do
stub_lfs_object_storage(proxy_download: false) stub_lfs_object_storage(proxy_download: false)
lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE) lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE)
end end
...@@ -128,10 +104,10 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -128,10 +104,10 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when deploy key is authorized' do context 'when deploy key is authorized' do
let(:key) { create(:deploy_key) } let_it_be(:key) { create(:deploy_key) }
let(:authorization) { authorize_deploy_key } let(:authorization) { authorize_deploy_key }
let(:update_permissions) do before do
project.deploy_keys << key project.deploy_keys << key
end end
...@@ -142,20 +118,20 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -142,20 +118,20 @@ RSpec.describe 'Git LFS API and storage' do
let(:authorization) { authorize_user_key } let(:authorization) { authorize_user_key }
context 'when user allowed' do context 'when user allowed' do
let(:update_permissions) do before do
project.add_maintainer(user) authorize_download
end end
it_behaves_like 'LFS http 200 blob response' it_behaves_like 'LFS http 200 blob response'
context 'when user password is expired' do context 'when user password is expired' do
let(:user) { create(:user, password_expires_at: 1.minute.ago)} let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
context 'when user is blocked' do context 'when user is blocked' do
let(:user) { create(:user, :blocked)} let_it_be(:user) { create(:user, :blocked)}
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
...@@ -168,19 +144,19 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -168,19 +144,19 @@ RSpec.describe 'Git LFS API and storage' do
context 'when build is authorized as' do context 'when build is authorized as' do
let(:authorization) { authorize_ci_project } let(:authorization) { authorize_ci_project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
shared_examples 'can download LFS only from own projects' do shared_examples 'can download LFS only from own projects' do
context 'for owned project' do context 'for owned project' do
let(:project) { create(:project, namespace: user.namespace) } let_it_be(:project) { create(:project, namespace: user.namespace) }
it_behaves_like 'LFS http 200 blob response' it_behaves_like 'LFS http 200 blob response'
end end
context 'for member of project' do context 'for member of project' do
let(:pipeline) { create(:ci_empty_pipeline, project: project) } before do
authorize_download
let(:update_permissions) do
project.add_reporter(user)
end end
it_behaves_like 'LFS http 200 blob response' it_behaves_like 'LFS http 200 blob response'
...@@ -196,15 +172,12 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -196,15 +172,12 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'administrator', :enable_admin_mode do context 'administrator', :enable_admin_mode do
let(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
it_behaves_like 'can download LFS only from own projects' it_behaves_like 'can download LFS only from own projects'
end end
context 'regular user' do context 'regular user' do
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
it_behaves_like 'can download LFS only from own projects' it_behaves_like 'can download LFS only from own projects'
end end
...@@ -217,15 +190,14 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -217,15 +190,14 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'when handling LFS batch request' do describe 'when handling LFS batch request' do
let(:update_lfs_permissions) { } subject(:request) { post_lfs_json batch_url(project), body, headers }
let(:update_user_permissions) { }
let(:response) { request && super() }
let(:lfs_chunked_encoding) { true } let(:lfs_chunked_encoding) { true }
before do before do
update_lfs_permissions
update_user_permissions
stub_feature_flags(lfs_chunked_encoding: lfs_chunked_encoding) stub_feature_flags(lfs_chunked_encoding: lfs_chunked_encoding)
post_lfs_json batch_url(project), body, headers project.lfs_objects << lfs_object
end end
shared_examples 'process authorization header' do |renew_authorization:| shared_examples 'process authorization header' do |renew_authorization:|
...@@ -239,7 +211,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -239,7 +211,7 @@ RSpec.describe 'Git LFS API and storage' do
expect(response_authorization).not_to eq(authorization) expect(response_authorization).not_to eq(authorization)
end end
it 'returns a a valid token' do it 'returns a valid token' do
username, token = ::Base64.decode64(response_authorization.split(' ', 2).last).split(':', 2) username, token = ::Base64.decode64(response_authorization.split(' ', 2).last).split(':', 2)
expect(username).to eq(user.username) expect(username).to eq(user.username)
...@@ -276,10 +248,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -276,10 +248,6 @@ RSpec.describe 'Git LFS API and storage' do
shared_examples 'an authorized request' do |renew_authorization:| shared_examples 'an authorized request' do |renew_authorization:|
context 'when downloading an LFS object that is assigned to our project' do context 'when downloading an LFS object that is assigned to our project' do
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
it 'with href to download' do it 'with href to download' do
...@@ -291,8 +259,8 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -291,8 +259,8 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when downloading an LFS object that is assigned to other project' do context 'when downloading an LFS object that is assigned to other project' do
let(:update_lfs_permissions) do before do
other_project.lfs_objects << lfs_object lfs_object.update!(projects: [other_project])
end end
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
...@@ -314,15 +282,12 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -314,15 +282,12 @@ RSpec.describe 'Git LFS API and storage' do
end end
end end
context 'when downloading one new and one existing LFS object' do context 'when downloading one existing and one missing LFS object' do
let(:body) { download_body(multiple_objects) } let(:body) { download_body(multiple_objects) }
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
it 'responds with download hypermedia link for the new object' do it 'responds with download hypermedia link for the existing object' do
expect(json_response['objects'].first).to include(sample_object) expect(json_response['objects'].first).to include(sample_object)
expect(json_response['objects'].first['actions']['download']).to include('href' => objects_url(project, sample_oid)) expect(json_response['objects'].first['actions']['download']).to include('href' => objects_url(project, sample_oid))
expect(json_response['objects'].last).to eq({ expect(json_response['objects'].last).to eq({
...@@ -341,8 +306,9 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -341,8 +306,9 @@ RSpec.describe 'Git LFS API and storage' do
context 'when downloading two existing LFS objects' do context 'when downloading two existing LFS objects' do
let(:body) { download_body(multiple_objects) } let(:body) { download_body(multiple_objects) }
let(:other_object) { create(:lfs_object, :with_file, oid: non_existing_object_oid, size: non_existing_object_size) } let(:other_object) { create(:lfs_object, :with_file, oid: non_existing_object_oid, size: non_existing_object_size) }
let(:update_lfs_permissions) do
project.lfs_objects << [lfs_object, other_object] before do
project.lfs_objects << other_object
end end
it 'responds with the download hypermedia link for each object' do it 'responds with the download hypermedia link for each object' do
...@@ -358,10 +324,8 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -358,10 +324,8 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user is authenticated' do context 'when user is authenticated' do
let(:authorization) { authorize_user } before do
project.add_role(user, role) if role
let(:update_user_permissions) do
project.add_role(user, role)
end end
it_behaves_like 'an authorized request', renew_authorization: true do it_behaves_like 'an authorized request', renew_authorization: true do
...@@ -369,7 +333,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -369,7 +333,7 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user is not a member of the project' do context 'when user is not a member of the project' do
let(:update_user_permissions) { nil } let(:role) { nil }
it_behaves_like 'LFS http 404 response' it_behaves_like 'LFS http 404 response'
end end
...@@ -381,18 +345,17 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -381,18 +345,17 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user password is expired' do context 'when user password is expired' do
let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
let(:role) { :reporter} let(:role) { :reporter}
let(:user) { create(:user, password_expires_at: 1.minute.ago)}
it 'with an 404 for specific object' do # TODO: This should return a 404 response
expect(json_response['objects'].first).to include(sample_object) # https://gitlab.com/gitlab-org/gitlab/-/issues/292006
expect(json_response['objects'].first['error']).to include('code' => 404, 'message' => "Object does not exist on the server or you don't have permissions to access it") it_behaves_like 'LFS http 200 response'
end
end end
context 'when user is blocked' do context 'when user is blocked' do
let_it_be(:user) { create(:user, :blocked)}
let(:role) { :reporter} let(:role) { :reporter}
let(:user) { create(:user, :blocked)}
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
...@@ -400,11 +363,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -400,11 +363,6 @@ RSpec.describe 'Git LFS API and storage' do
context 'when using Deploy Tokens' do context 'when using Deploy Tokens' do
let(:authorization) { authorize_deploy_token } let(:authorization) { authorize_deploy_token }
let(:update_user_permissions) { nil }
let(:role) { nil }
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
context 'when Deploy Token is not valid' do context 'when Deploy Token is not valid' do
let(:deploy_token) { create(:deploy_token, projects: [project], read_repository: false) } let(:deploy_token) { create(:deploy_token, projects: [project], read_repository: false) }
...@@ -429,16 +387,12 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -429,16 +387,12 @@ RSpec.describe 'Git LFS API and storage' do
context 'when build is authorized as' do context 'when build is authorized as' do
let(:authorization) { authorize_ci_project } let(:authorization) { authorize_ci_project }
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
shared_examples 'can download LFS only from own projects' do |renew_authorization:| shared_examples 'can download LFS only from own projects' do |renew_authorization:|
context 'for own project' do context 'for own project' do
let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:update_user_permissions) do before do
project.add_reporter(user) authorize_download
end end
it_behaves_like 'an authorized request', renew_authorization: renew_authorization it_behaves_like 'an authorized request', renew_authorization: renew_authorization
...@@ -454,7 +408,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -454,7 +408,7 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'administrator', :enable_admin_mode do context 'administrator', :enable_admin_mode do
let(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
it_behaves_like 'can download LFS only from own projects', renew_authorization: true it_behaves_like 'can download LFS only from own projects', renew_authorization: true
...@@ -474,12 +428,10 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -474,12 +428,10 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user is not authenticated' do context 'when user is not authenticated' do
describe 'is accessing public project' do let(:authorization) { nil }
let(:project) { create(:project, :public) }
let(:update_lfs_permissions) do describe 'is accessing public project' do
project.lfs_objects << lfs_object let_it_be(:project) { create(:project, :public) }
end
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
...@@ -503,17 +455,13 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -503,17 +455,13 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'is accessing non-public project' do describe 'is accessing non-public project' do
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
end end
end end
describe 'upload' do describe 'upload' do
let(:project) { create(:project, :public) } let_it_be(:project) { create(:project, :public) }
let(:body) { upload_body(sample_object) } let(:body) { upload_body(sample_object) }
shared_examples 'pushes new LFS objects' do |renew_authorization:| shared_examples 'pushes new LFS objects' do |renew_authorization:|
...@@ -551,17 +499,15 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -551,17 +499,15 @@ RSpec.describe 'Git LFS API and storage' do
describe 'when request is authenticated' do describe 'when request is authenticated' do
describe 'when user has project push access' do describe 'when user has project push access' do
let(:authorization) { authorize_user } before do
authorize_upload
let(:update_user_permissions) do
project.add_developer(user)
end end
context 'when pushing an LFS object that already exists' do context 'when pushing an LFS object that already exists' do
shared_examples_for 'batch upload with existing LFS object' do shared_examples_for 'batch upload with existing LFS object' do
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
it 'responds with links the object to the project' do it 'responds with links to the object in the project' do
expect(json_response['objects']).to be_kind_of(Array) expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first).to include(sample_object) expect(json_response['objects'].first).to include(sample_object)
expect(lfs_object.projects.pluck(:id)).not_to include(project.id) expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
...@@ -576,17 +522,21 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -576,17 +522,21 @@ RSpec.describe 'Git LFS API and storage' do
it_behaves_like 'process authorization header', renew_authorization: true it_behaves_like 'process authorization header', renew_authorization: true
end end
let(:update_lfs_permissions) do context 'in another project' do
other_project.lfs_objects << lfs_object before do
lfs_object.update!(projects: [other_project])
end end
context 'in another project' do
it_behaves_like 'batch upload with existing LFS object' it_behaves_like 'batch upload with existing LFS object'
end end
context 'in source of fork project' do context 'in source of fork project' do
let(:project) { fork_project(other_project) } let(:project) { fork_project(other_project) }
before do
lfs_object.update!(projects: [other_project])
end
it_behaves_like 'batch upload with existing LFS object' it_behaves_like 'batch upload with existing LFS object'
end end
end end
...@@ -597,9 +547,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -597,9 +547,6 @@ RSpec.describe 'Git LFS API and storage' do
context 'when pushing one new and one existing LFS object' do context 'when pushing one new and one existing LFS object' do
let(:body) { upload_body(multiple_objects) } let(:body) { upload_body(multiple_objects) }
let(:update_lfs_permissions) do
project.lfs_objects << lfs_object
end
it_behaves_like 'LFS http 200 response' it_behaves_like 'LFS http 200 response'
...@@ -622,13 +569,12 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -622,13 +569,12 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user does not have push access' do context 'when user does not have push access' do
let(:authorization) { authorize_user }
it_behaves_like 'LFS http 403 response' it_behaves_like 'LFS http 403 response'
end end
context 'when build is authorized' do context 'when build is authorized' do
let(:authorization) { authorize_ci_project } let(:authorization) { authorize_ci_project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
context 'build has an user' do context 'build has an user' do
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
...@@ -656,7 +602,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -656,7 +602,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:key) { create(:deploy_key) } let(:key) { create(:deploy_key) }
let(:authorization) { authorize_deploy_key } let(:authorization) { authorize_deploy_key }
let(:update_user_permissions) do before do
project.deploy_keys_projects.create!(deploy_key: key, can_push: true) project.deploy_keys_projects.create!(deploy_key: key, can_push: true)
end end
...@@ -665,9 +611,11 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -665,9 +611,11 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'when user is not authenticated' do context 'when user is not authenticated' do
let(:authorization) { nil }
context 'when user has push access' do context 'when user has push access' do
let(:update_user_permissions) do before do
project.add_maintainer(user) authorize_upload
end end
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
...@@ -680,7 +628,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -680,7 +628,6 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'unsupported' do describe 'unsupported' do
let(:authorization) { authorize_user }
let(:body) { request_body('other', sample_object) } let(:body) { request_body('other', sample_object) }
it_behaves_like 'LFS http 404 response' it_behaves_like 'LFS http 404 response'
...@@ -688,8 +635,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -688,8 +635,6 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'when handling LFS batch request on a read-only GitLab instance' do describe 'when handling LFS batch request on a read-only GitLab instance' do
let(:authorization) { authorize_user }
subject { post_lfs_json(batch_url(project), body, headers) } subject { post_lfs_json(batch_url(project), body, headers) }
before do before do
...@@ -717,6 +662,8 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -717,6 +662,8 @@ RSpec.describe 'Git LFS API and storage' do
end end
describe 'when pushing a LFS object' do describe 'when pushing a LFS object' do
let(:include_workhorse_jwt_header) { true }
shared_examples 'unauthorized' do shared_examples 'unauthorized' do
context 'and request is sent by gitlab-workhorse to authorize the request' do context 'and request is sent by gitlab-workhorse to authorize the request' do
before do before do
...@@ -771,8 +718,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -771,8 +718,6 @@ RSpec.describe 'Git LFS API and storage' do
describe 'to one project' do describe 'to one project' do
describe 'when user is authenticated' do describe 'when user is authenticated' do
let(:authorization) { authorize_user }
describe 'when user has push access to the project' do describe 'when user has push access to the project' do
before do before do
project.add_developer(user) project.add_developer(user)
...@@ -978,6 +923,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -978,6 +923,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'when build is authorized' do context 'when build is authorized' do
let(:authorization) { authorize_ci_project } let(:authorization) { authorize_ci_project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
context 'build has an user' do context 'build has an user' do
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
...@@ -1025,13 +971,13 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -1025,13 +971,13 @@ RSpec.describe 'Git LFS API and storage' do
it_behaves_like 'LFS http 200 workhorse response' it_behaves_like 'LFS http 200 workhorse response'
context 'when user password is expired' do context 'when user password is expired' do
let(:user) { create(:user, password_expires_at: 1.minute.ago)} let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
context 'when user is blocked' do context 'when user is blocked' do
let(:user) { create(:user, :blocked)} let_it_be(:user) { create(:user, :blocked)}
it_behaves_like 'LFS http 401 response' it_behaves_like 'LFS http 401 response'
end end
...@@ -1047,18 +993,18 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -1047,18 +993,18 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'for unauthenticated' do context 'for unauthenticated' do
let(:authorization) { nil }
it_behaves_like 'unauthorized' it_behaves_like 'unauthorized'
end end
end end
describe 'to a forked project' do describe 'to a forked project' do
let(:upstream_project) { create(:project, :public) } let_it_be(:upstream_project) { create(:project, :public) }
let(:project_owner) { create(:user) } let_it_be(:project_owner) { create(:user) }
let(:project) { fork_project(upstream_project, project_owner) } let(:project) { fork_project(upstream_project, project_owner) }
describe 'when user is authenticated' do describe 'when user is authenticated' do
let(:authorization) { authorize_user }
describe 'when user has push access to the project' do describe 'when user has push access to the project' do
before do before do
project.add_developer(user) project.add_developer(user)
...@@ -1098,6 +1044,7 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -1098,6 +1044,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'when build is authorized' do context 'when build is authorized' do
let(:authorization) { authorize_ci_project } let(:authorization) { authorize_ci_project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
before do before do
put_authorize put_authorize
...@@ -1126,12 +1073,13 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -1126,12 +1073,13 @@ RSpec.describe 'Git LFS API and storage' do
end end
context 'for unauthenticated' do context 'for unauthenticated' do
let(:authorization) { nil }
it_behaves_like 'unauthorized' it_behaves_like 'unauthorized'
end end
describe 'and second project not related to fork or a source project' do describe 'and second project not related to fork or a source project' do
let(:second_project) { create(:project) } let_it_be(:second_project) { create(:project) }
let(:authorization) { authorize_user }
before do before do
second_project.add_maintainer(user) second_project.add_maintainer(user)
...@@ -1197,13 +1145,6 @@ RSpec.describe 'Git LFS API and storage' do ...@@ -1197,13 +1145,6 @@ RSpec.describe 'Git LFS API and storage' do
"#{sample_oid}012345678" "#{sample_oid}012345678"
end end
end end
context 'with projects' do
it_behaves_like 'LFS http requests' do
let(:container) { project }
let(:authorize_guest) { project.add_guest(user) }
let(:authorize_download) { project.add_reporter(user) }
let(:authorize_upload) { project.add_developer(user) }
end end
end end
......
# frozen_string_literal: true
RSpec.shared_examples Repositories::GitHttpController do
include GitHttpHelpers
let(:repository_path) { "#{container.full_path}.git" }
let(:params) { { repository_path: repository_path } }
describe 'HEAD #info_refs' do
it 'returns 403' do
head :info_refs, params: params
expect(response).to have_gitlab_http_status(:forbidden)
end
end
describe 'GET #info_refs' do
let(:params) { super().merge(service: 'git-upload-pack') }
it 'returns 401 for unauthenticated requests to public repositories when http protocol is disabled' do
stub_application_setting(enabled_git_access_protocol: 'ssh')
allow(controller).to receive(:basic_auth_provided?).and_call_original
expect(controller).to receive(:http_download_allowed?).and_call_original
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'calls the right access checker class with the right object' do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
access_double = double
options = {
authentication_abilities: [:download_code],
repository_path: repository_path,
redirected_path: nil,
auth_result_type: :none
}
expect(access_checker_class).to receive(:new)
.with(nil, container, 'http', hash_including(options))
.and_return(access_double)
allow(access_double).to receive(:check).and_return(false)
get :info_refs, params: params
end
context 'with authorized user' do
before do
request.headers.merge! auth_env(user.username, user.password, nil)
end
it 'returns 200' do
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:ok)
end
it 'updates the user activity' do
expect_next_instance_of(Users::ActivityService) do |activity_service|
expect(activity_service).to receive(:execute)
end
get :info_refs, params: params
end
include_context 'parsed logs' do
it 'adds user info to the logs' do
get :info_refs, params: params
expect(log_data).to include('username' => user.username,
'user_id' => user.id,
'meta.user' => user.username)
end
end
end
context 'with exceptions' do
before do
allow(controller).to receive(:authenticate_user).and_return(true)
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
end
it 'returns 503 with GRPC Unavailable' do
allow(controller).to receive(:access_check).and_raise(GRPC::Unavailable)
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:service_unavailable)
end
it 'returns 503 with timeout error' do
allow(controller).to receive(:access_check).and_raise(Gitlab::GitAccess::TimeoutError)
get :info_refs, params: params
expect(response).to have_gitlab_http_status(:service_unavailable)
expect(response.body).to eq 'Gitlab::GitAccess::TimeoutError'
end
end
end
describe 'POST #git_upload_pack' do
before do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
end
it 'returns 200' do
post :git_upload_pack, params: params
expect(response).to have_gitlab_http_status(:ok)
end
end
end
...@@ -65,12 +65,19 @@ end ...@@ -65,12 +65,19 @@ end
RSpec.shared_examples 'LFS http requests' do RSpec.shared_examples 'LFS http requests' do
include LfsHttpHelpers include LfsHttpHelpers
let(:lfs_enabled) { true }
let(:authorize_guest) {} let(:authorize_guest) {}
let(:authorize_download) {} let(:authorize_download) {}
let(:authorize_upload) {} let(:authorize_upload) {}
let(:lfs_object) { create(:lfs_object, :with_file) } let(:lfs_object) { create(:lfs_object, :with_file) }
let(:sample_oid) { lfs_object.oid } let(:sample_oid) { lfs_object.oid }
let(:sample_size) { lfs_object.size }
let(:sample_object) { { 'oid' => sample_oid, 'size' => sample_size } }
let(:non_existing_object_oid) { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
let(:non_existing_object_size) { 1575078 }
let(:non_existing_object) { { 'oid' => non_existing_object_oid, 'size' => non_existing_object_size } }
let(:multiple_objects) { [sample_object, non_existing_object] }
let(:authorization) { authorize_user } let(:authorization) { authorize_user }
let(:headers) do let(:headers) do
...@@ -89,13 +96,11 @@ RSpec.shared_examples 'LFS http requests' do ...@@ -89,13 +96,11 @@ RSpec.shared_examples 'LFS http requests' do
end end
before do before do
stub_lfs_setting(enabled: true) stub_lfs_setting(enabled: lfs_enabled)
end end
context 'when LFS is disabled globally' do context 'when LFS is disabled globally' do
before do let(:lfs_enabled) { false }
stub_lfs_setting(enabled: false)
end
describe 'download request' do describe 'download request' do
before do before do
......
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