2019-07-31 22:56:46 +05:30
# frozen_string_literal: true
2016-04-02 18:10:28 +05:30
require 'spec_helper'
2023-04-23 21:23:45 +05:30
RSpec . describe Projects :: ImportService , feature_category : :importers do
2017-09-10 17:25:29 +05:30
let! ( :project ) { create ( :project ) }
2016-04-02 18:10:28 +05:30
let ( :user ) { project . creator }
subject { described_class . new ( project , user ) }
2018-11-08 19:23:39 +05:30
before do
allow ( project ) . to receive ( :lfs_enabled? ) . and_return ( true )
end
2018-03-17 18:26:18 +05:30
describe '#async?' do
it 'returns true for an asynchronous importer' do
importer_class = double ( :importer , async? : true )
allow ( subject ) . to receive ( :has_importer? ) . and_return ( true )
allow ( subject ) . to receive ( :importer_class ) . and_return ( importer_class )
expect ( subject ) . to be_async
end
it 'returns false for a regular importer' do
importer_class = double ( :importer , async? : false )
allow ( subject ) . to receive ( :has_importer? ) . and_return ( true )
allow ( subject ) . to receive ( :importer_class ) . and_return ( importer_class )
expect ( subject ) . not_to be_async
end
it 'returns false when the importer does not define #async?' do
importer_class = double ( :importer )
allow ( subject ) . to receive ( :has_importer? ) . and_return ( true )
allow ( subject ) . to receive ( :importer_class ) . and_return ( importer_class )
expect ( subject ) . not_to be_async
end
it 'returns false when the importer does not exist' do
allow ( subject ) . to receive ( :has_importer? ) . and_return ( false )
expect ( subject ) . not_to be_async
end
end
2016-04-02 18:10:28 +05:30
describe '#execute' do
context 'with unknown url' do
before do
project . import_url = Project :: UNKNOWN_IMPORT_URL
end
it 'succeeds if repository is created successfully' do
expect ( project ) . to receive ( :create_repository ) . and_return ( true )
result = subject . execute
expect ( result [ :status ] ) . to eq :success
end
it 'fails if repository creation fails' do
expect ( project ) . to receive ( :create_repository ) . and_return ( false )
result = subject . execute
expect ( result [ :status ] ) . to eq :error
2018-11-08 19:23:39 +05:30
expect ( result [ :message ] ) . to eq " Error importing repository #{ project . safe_import_url } into #{ project . full_path } - The repository could not be created. "
end
context 'when repository creation succeeds' do
it 'does not download lfs files' do
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . not_to receive ( :execute )
subject . execute
end
2016-04-02 18:10:28 +05:30
end
end
context 'with known url' do
before do
project . import_url = 'https://github.com/vim/vim.git'
2017-08-17 22:00:37 +05:30
project . import_type = 'github'
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
context 'with a Github repository' do
2021-11-18 22:05:49 +05:30
it 'tracks the start of import' do
expect ( Gitlab :: GithubImport :: ParallelImporter ) . to receive ( :track_start_import )
subject . execute
end
2018-03-17 18:26:18 +05:30
it 'succeeds if repository import was scheduled' do
expect_any_instance_of ( Gitlab :: GithubImport :: ParallelImporter )
. to receive ( :execute )
. and_return ( true )
2016-04-02 18:10:28 +05:30
2017-08-17 22:00:37 +05:30
result = subject . execute
2016-04-02 18:10:28 +05:30
2017-08-17 22:00:37 +05:30
expect ( result [ :status ] ) . to eq :success
end
2018-03-17 18:26:18 +05:30
it 'fails if repository import was not scheduled' do
expect_any_instance_of ( Gitlab :: GithubImport :: ParallelImporter )
. to receive ( :execute )
. and_return ( false )
2017-08-17 22:00:37 +05:30
result = subject . execute
expect ( result [ :status ] ) . to eq :error
end
2018-11-08 19:23:39 +05:30
context 'when repository import scheduled' do
it 'does not download lfs objects' do
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . not_to receive ( :execute )
subject . execute
end
end
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
context 'with a non Github repository' do
before do
project . import_url = 'https://bitbucket.org/vim/vim.git'
project . import_type = 'bitbucket'
end
2016-04-02 18:10:28 +05:30
2023-01-10 11:22:00 +05:30
context 'when importer supports refmap' do
before do
project . import_type = 'gitea'
2020-04-22 19:07:51 +05:30
end
2023-01-10 11:22:00 +05:30
it 'succeeds if repository fetch as mirror is successful' do
expect ( project ) . to receive ( :ensure_repository )
expect ( project . repository ) . to receive ( :fetch_as_mirror ) . with ( 'https://bitbucket.org/vim/vim.git' , refmap : Gitlab :: LegacyGithubImport :: Importer . refmap , resolved_address : '' ) . and_return ( true )
expect_next_instance_of ( Gitlab :: LegacyGithubImport :: Importer ) do | importer |
expect ( importer ) . to receive ( :execute ) . and_return ( true )
end
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq :success
2020-04-22 19:07:51 +05:30
end
2016-04-02 18:10:28 +05:30
2023-01-10 11:22:00 +05:30
it 'fails if repository fetch as mirror fails' do
expect ( project ) . to receive ( :ensure_repository )
expect ( project . repository )
. to receive ( :fetch_as_mirror )
. and_raise ( Gitlab :: Git :: CommandError , 'Failed to import the repository /a/b/c' )
2017-08-17 22:00:37 +05:30
2023-01-10 11:22:00 +05:30
result = subject . execute
expect ( result [ :status ] ) . to eq :error
expect ( result [ :message ] ) . to eq " Error importing repository #{ project . safe_import_url } into #{ project . full_path } - Failed to import the repository [FILTERED] "
end
2017-08-17 22:00:37 +05:30
end
2023-01-10 11:22:00 +05:30
context 'when importer does not support refmap' do
it 'succeeds if repository import is successful' do
expect ( project . repository ) . to receive ( :import_repository ) . and_return ( true )
expect_next_instance_of ( Gitlab :: BitbucketImport :: Importer ) do | importer |
expect ( importer ) . to receive ( :execute ) . and_return ( true )
end
2017-08-17 22:00:37 +05:30
2023-01-10 11:22:00 +05:30
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
2017-08-17 22:00:37 +05:30
2023-01-10 11:22:00 +05:30
result = subject . execute
expect ( result [ :status ] ) . to eq :success
end
it 'fails if repository import fails' do
expect ( project . repository )
. to receive ( :import_repository )
. with ( 'https://bitbucket.org/vim/vim.git' , resolved_address : '' )
. and_raise ( Gitlab :: Git :: CommandError , 'Failed to import the repository /a/b/c' )
result = subject . execute
expect ( result [ :status ] ) . to eq :error
expect ( result [ :message ] ) . to eq " Error importing repository #{ project . safe_import_url } into #{ project . full_path } - Failed to import the repository [FILTERED] "
end
2018-11-08 19:23:39 +05:30
end
2019-07-31 22:56:46 +05:30
context 'when lfs import fails' do
it 'logs the error' do
error_message = 'error message'
2020-04-08 14:13:33 +05:30
expect ( project . repository ) . to receive ( :import_repository ) . and_return ( true )
2020-04-22 19:07:51 +05:30
expect_next_instance_of ( Gitlab :: BitbucketImport :: Importer ) do | importer |
expect ( importer ) . to receive ( :execute ) . and_return ( true )
end
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :error , message : error_message )
end
2019-07-31 22:56:46 +05:30
expect ( Gitlab :: AppLogger ) . to receive ( :error ) . with ( " The Lfs import process failed. #{ error_message } " )
subject . execute
end
end
2018-11-08 19:23:39 +05:30
context 'when repository import scheduled' do
before do
2020-04-08 14:13:33 +05:30
expect ( project . repository ) . to receive ( :import_repository ) . and_return ( true )
2018-11-08 19:23:39 +05:30
allow ( subject ) . to receive ( :import_data )
end
it 'downloads lfs objects if lfs_enabled is enabled for project' do
allow ( project ) . to receive ( :lfs_enabled? ) . and_return ( true )
2019-02-02 18:00:53 +05:30
2019-07-31 22:56:46 +05:30
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . to receive ( :execute )
2018-11-08 19:23:39 +05:30
subject . execute
end
it 'does not download lfs objects if lfs_enabled is not enabled for project' do
allow ( project ) . to receive ( :lfs_enabled? ) . and_return ( false )
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . not_to receive ( :execute )
subject . execute
end
2017-08-17 22:00:37 +05:30
end
2016-04-02 18:10:28 +05:30
end
end
context 'with valid importer' do
before do
2022-05-07 20:08:51 +05:30
provider = double ( :provider ) . as_null_object
stub_omniauth_setting ( providers : [ provider ] )
2016-04-02 18:10:28 +05:30
project . import_url = 'https://github.com/vim/vim.git'
project . import_type = 'github'
2022-05-07 20:08:51 +05:30
allow ( project ) . to receive ( :import_data ) . and_return ( double ( :import_data ) . as_null_object )
2016-04-02 18:10:28 +05:30
end
it 'succeeds if importer succeeds' do
2018-03-17 18:26:18 +05:30
allow_any_instance_of ( Gitlab :: GithubImport :: ParallelImporter )
. to receive ( :execute ) . and_return ( true )
2016-04-02 18:10:28 +05:30
result = subject . execute
expect ( result [ :status ] ) . to eq :success
end
it 'fails if importer fails' do
2018-03-17 18:26:18 +05:30
allow_any_instance_of ( Gitlab :: GithubImport :: ParallelImporter )
. to receive ( :execute )
. and_return ( false )
2016-04-02 18:10:28 +05:30
result = subject . execute
expect ( result [ :status ] ) . to eq :error
2016-11-03 12:29:30 +05:30
end
2018-11-08 19:23:39 +05:30
context 'when importer' do
it 'has a custom repository importer it does not download lfs objects' do
allow ( Gitlab :: GithubImport :: ParallelImporter ) . to receive ( :imports_repository? ) . and_return ( true )
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . not_to receive ( :execute )
subject . execute
end
it 'does not have a custom repository importer downloads lfs objects' do
allow ( Gitlab :: GithubImport :: ParallelImporter ) . to receive ( :imports_repository? ) . and_return ( false )
2019-07-31 22:56:46 +05:30
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . to receive ( :execute )
2018-11-08 19:23:39 +05:30
subject . execute
end
2019-07-31 22:56:46 +05:30
context 'when lfs import fails' do
it 'logs the error' do
error_message = 'error message'
allow ( Gitlab :: GithubImport :: ParallelImporter ) . to receive ( :imports_repository? ) . and_return ( false )
expect_any_instance_of ( Projects :: LfsPointers :: LfsImportService ) . to receive ( :execute ) . and_return ( status : :error , message : error_message )
expect ( Gitlab :: AppLogger ) . to receive ( :error ) . with ( " The Lfs import process failed. #{ error_message } " )
subject . execute
end
end
2018-11-08 19:23:39 +05:30
end
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
context 'with blocked import_URL' do
it 'fails with localhost' do
project . import_url = 'https://localhost:9000/vim/vim.git'
result = described_class . new ( project , user ) . execute
expect ( result [ :status ] ) . to eq :error
2018-05-09 12:01:36 +05:30
expect ( result [ :message ] ) . to include ( 'Requests to localhost are not allowed' )
2017-08-17 22:00:37 +05:30
end
it 'fails with port 25' do
project . import_url = " https://github.com:25/vim/vim.git "
2020-05-24 23:13:21 +05:30
result = subject . execute
2017-08-17 22:00:37 +05:30
expect ( result [ :status ] ) . to eq :error
2018-12-13 13:39:08 +05:30
expect ( result [ :message ] ) . to include ( 'Only allowed ports are 80, 443' )
2017-08-17 22:00:37 +05:30
end
2022-11-25 23:54:43 +05:30
it 'fails with file scheme' do
project . import_url = " file:///tmp/dir.git "
result = subject . execute
expect ( result [ :status ] ) . to eq :error
expect ( result [ :message ] ) . to include ( 'Only allowed schemes are http, https' )
end
2017-08-17 22:00:37 +05:30
end
2023-01-10 11:22:00 +05:30
context 'when DNS rebind protection is disabled' do
before do
allow ( Gitlab :: CurrentSettings ) . to receive ( :dns_rebinding_protection_enabled? ) . and_return ( false )
project . import_url = " https://example.com/group/project "
allow ( Gitlab :: UrlBlocker ) . to receive ( :validate! )
. with ( project . import_url , ports : Project :: VALID_IMPORT_PORTS , schemes : Project :: VALID_IMPORT_PROTOCOLS , dns_rebind_protection : false )
. and_return ( [ Addressable :: URI . parse ( " https://example.com/group/project " ) , nil ] )
end
it 'imports repository with url without additional resolved address' do
expect ( project . repository ) . to receive ( :import_repository ) . with ( 'https://example.com/group/project' , resolved_address : '' ) . and_return ( true )
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq ( :success )
end
end
context 'when DNS rebind protection is enabled' do
before do
allow ( Gitlab :: CurrentSettings ) . to receive ( :http_proxy_env? ) . and_return ( false )
allow ( Gitlab :: CurrentSettings ) . to receive ( :dns_rebinding_protection_enabled? ) . and_return ( true )
end
context 'when https url is provided' do
before do
project . import_url = " https://example.com/group/project "
allow ( Gitlab :: UrlBlocker ) . to receive ( :validate! )
. with ( project . import_url , ports : Project :: VALID_IMPORT_PORTS , schemes : Project :: VALID_IMPORT_PROTOCOLS , dns_rebind_protection : true )
. and_return ( [ Addressable :: URI . parse ( " https://172.16.123.1/group/project " ) , 'example.com' ] )
end
it 'imports repository with url and additional resolved address' do
expect ( project . repository ) . to receive ( :import_repository ) . with ( 'https://example.com/group/project' , resolved_address : '172.16.123.1' ) . and_return ( true )
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq ( :success )
end
2023-03-17 16:20:25 +05:30
context 'when host resolves to an IPv6 address' do
before do
project . import_url = 'https://gitlab.com/gitlab-org/gitlab-development-kit'
allow ( Gitlab :: UrlBlocker ) . to receive ( :validate! )
. with ( project . import_url , ports : Project :: VALID_IMPORT_PORTS , schemes : Project :: VALID_IMPORT_PROTOCOLS , dns_rebind_protection : true )
. and_return ( [ Addressable :: URI . parse ( 'https://[2606:4700:90:0:f22e:fbec:5bed:a9b9]/gitlab-org/gitlab-development-kit' ) , 'gitlab.com' ] )
end
it 'imports repository with url and additional resolved bare IPv6 address' do
expect ( project . repository ) . to receive ( :import_repository ) . with ( 'https://gitlab.com/gitlab-org/gitlab-development-kit' , resolved_address : '2606:4700:90:0:f22e:fbec:5bed:a9b9' ) . and_return ( true )
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq ( :success )
end
end
2023-01-10 11:22:00 +05:30
end
context 'when http url is provided' do
before do
project . import_url = " http://example.com/group/project "
allow ( Gitlab :: UrlBlocker ) . to receive ( :validate! )
. with ( project . import_url , ports : Project :: VALID_IMPORT_PORTS , schemes : Project :: VALID_IMPORT_PROTOCOLS , dns_rebind_protection : true )
. and_return ( [ Addressable :: URI . parse ( " http://172.16.123.1/group/project " ) , 'example.com' ] )
end
it 'imports repository with url and additional resolved address' do
expect ( project . repository ) . to receive ( :import_repository ) . with ( 'http://example.com/group/project' , resolved_address : '172.16.123.1' ) . and_return ( true )
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq ( :success )
end
end
context 'when git address is provided' do
before do
project . import_url = " git://example.com/group/project.git "
allow ( Gitlab :: UrlBlocker ) . to receive ( :validate! )
. with ( project . import_url , ports : Project :: VALID_IMPORT_PORTS , schemes : Project :: VALID_IMPORT_PROTOCOLS , dns_rebind_protection : true )
. and_return ( [ Addressable :: URI . parse ( " git://172.16.123.1/group/project " ) , 'example.com' ] )
end
it 'imports repository with url and without resolved address' do
expect ( project . repository ) . to receive ( :import_repository ) . with ( 'git://example.com/group/project.git' , resolved_address : '' ) . and_return ( true )
expect_next_instance_of ( Projects :: LfsPointers :: LfsImportService ) do | service |
expect ( service ) . to receive ( :execute ) . and_return ( status : :success )
end
result = subject . execute
expect ( result [ :status ] ) . to eq ( :success )
end
end
end
2016-04-02 18:10:28 +05:30
end
end