2020-07-28 23:09:34 +05:30
# frozen_string_literal: true
require 'spec_helper'
2023-03-04 22:38:38 +05:30
RSpec . describe API :: MavenPackages , feature_category : :package_registry do
2022-10-11 01:57:18 +05:30
using RSpec :: Parameterized :: TableSyntax
2020-07-28 23:09:34 +05:30
include WorkhorseHelpers
2023-07-09 08:55:56 +05:30
include HttpBasicAuthHelpers
2020-07-28 23:09:34 +05:30
2021-03-11 19:13:27 +05:30
include_context 'workhorse headers'
2021-03-08 18:12:59 +05:30
let_it_be_with_refind ( :package_settings ) { create ( :namespace_package_setting , :group ) }
2021-09-04 01:27:46 +05:30
let_it_be_with_refind ( :group ) { package_settings . namespace }
2020-07-28 23:09:34 +05:30
let_it_be ( :user ) { create ( :user ) }
let_it_be ( :project , reload : true ) { create ( :project , :public , namespace : group ) }
let_it_be ( :package , reload : true ) { create ( :maven_package , project : project , name : project . full_path ) }
let_it_be ( :maven_metadatum , reload : true ) { package . maven_metadatum }
let_it_be ( :package_file ) { package . package_files . with_file_name_like ( '%.xml' ) . first }
let_it_be ( :jar_file ) { package . package_files . with_file_name_like ( '%.jar' ) . first }
let_it_be ( :personal_access_token ) { create ( :personal_access_token , user : user ) }
2021-11-11 11:23:49 +05:30
let_it_be ( :job , reload : true ) { create ( :ci_build , user : user , status : :running , project : project ) }
2020-07-28 23:09:34 +05:30
let_it_be ( :deploy_token ) { create ( :deploy_token , read_package_registry : true , write_package_registry : true ) }
let_it_be ( :project_deploy_token ) { create ( :project_deploy_token , deploy_token : deploy_token , project : project ) }
2021-01-03 14:25:43 +05:30
let_it_be ( :deploy_token_for_group ) { create ( :deploy_token , :group , read_package_registry : true , write_package_registry : true ) }
let_it_be ( :group_deploy_token ) { create ( :group_deploy_token , deploy_token : deploy_token_for_group , group : group ) }
2020-07-28 23:09:34 +05:30
2023-05-27 22:25:52 +05:30
let ( :snowplow_gitlab_standard_context ) { { project : project , namespace : project . namespace , user : user , property : 'i_package_maven_user' } }
2023-03-04 22:38:38 +05:30
2021-03-08 18:12:59 +05:30
let ( :package_name ) { 'com/example/my-app' }
2021-03-11 19:13:27 +05:30
let ( :headers ) { workhorse_headers }
2020-07-28 23:09:34 +05:30
let ( :headers_with_token ) { headers . merge ( 'Private-Token' = > personal_access_token . token ) }
2021-01-03 14:25:43 +05:30
let ( :group_deploy_token_headers ) { { Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > deploy_token_for_group . token } }
2020-07-28 23:09:34 +05:30
let ( :headers_with_deploy_token ) do
headers . merge (
Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > deploy_token . token
)
end
let ( :version ) { '1.0-SNAPSHOT' }
2022-08-27 11:52:29 +05:30
let ( :param_path ) { " #{ package_name } / #{ version } " }
2020-07-28 23:09:34 +05:30
before do
project . add_developer ( user )
end
2022-10-11 01:57:18 +05:30
shared_examples 'handling groups and subgroups for' do | shared_example_name , visibilities : { public : :redirect } |
2021-09-04 01:27:46 +05:30
context 'within a group' do
2022-10-11 01:57:18 +05:30
visibilities . each do | visibility , not_found_response |
2021-09-04 01:27:46 +05:30
context " that is #{ visibility } " do
before do
group . update! ( visibility_level : Gitlab :: VisibilityLevel . level_value ( visibility . to_s ) )
end
2022-10-11 01:57:18 +05:30
it_behaves_like shared_example_name , not_found_response
2021-09-04 01:27:46 +05:30
end
end
end
context 'within a subgroup' do
let_it_be_with_reload ( :subgroup ) { create ( :group , parent : group ) }
before do
move_project_to_namespace ( subgroup )
end
2022-10-11 01:57:18 +05:30
visibilities . each do | visibility , not_found_response |
2021-09-04 01:27:46 +05:30
context " that is #{ visibility } " do
before do
subgroup . update! ( visibility_level : Gitlab :: VisibilityLevel . level_value ( visibility . to_s ) )
group . update! ( visibility_level : Gitlab :: VisibilityLevel . level_value ( visibility . to_s ) )
end
2022-10-11 01:57:18 +05:30
it_behaves_like shared_example_name , not_found_response
2021-09-04 01:27:46 +05:30
end
end
end
end
2022-10-11 01:57:18 +05:30
shared_examples 'handling groups, subgroups and user namespaces for' do | shared_example_name , visibilities : { public : :redirect } |
2021-09-04 01:27:46 +05:30
it_behaves_like 'handling groups and subgroups for' , shared_example_name , visibilities : visibilities
context 'within a user namespace' do
before do
move_project_to_namespace ( user . namespace )
end
visibilities . each do | visibility |
context " that is #{ visibility } " do
before do
user . namespace . update! ( visibility_level : Gitlab :: VisibilityLevel . level_value ( visibility . to_s ) )
end
it_behaves_like shared_example_name
end
end
end
end
2020-07-28 23:09:34 +05:30
shared_examples 'tracking the file download event' do
context 'with jar file' do
let_it_be ( :package_file ) { jar_file }
2021-01-03 14:25:43 +05:30
it_behaves_like 'a package tracking event' , described_class . name , 'pull_package'
2020-07-28 23:09:34 +05:30
end
end
2021-04-29 21:17:54 +05:30
shared_examples 'processing HEAD requests' do | instance_level : false |
2020-07-28 23:09:34 +05:30
subject { head api ( url ) }
before do
allow_any_instance_of ( :: Packages :: PackageFileUploader ) . to receive ( :fog_credentials ) . and_return ( object_storage_credentials )
stub_package_file_object_storage ( enabled : object_storage_enabled )
end
context 'with object storage enabled' do
let ( :object_storage_enabled ) { true }
before do
allow_any_instance_of ( :: Packages :: PackageFileUploader ) . to receive ( :file_storage? ) . and_return ( false )
end
context 'non AWS provider' do
let ( :object_storage_credentials ) { { provider : 'Google' } }
it 'does not generated a signed url for head' do
expect_any_instance_of ( Fog :: AWS :: Storage :: Files ) . not_to receive ( :head_url )
subject
2023-04-23 21:23:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :redirect )
2020-07-28 23:09:34 +05:30
end
end
context 'with AWS provider' do
let ( :object_storage_credentials ) { { provider : 'AWS' , aws_access_key_id : 'test' , aws_secret_access_key : 'test' } }
it 'generates a signed url for head' do
expect_any_instance_of ( Fog :: AWS :: Storage :: Files ) . to receive ( :head_url ) . and_call_original
subject
end
end
end
context 'with object storage disabled' do
let ( :object_storage_enabled ) { false }
let ( :object_storage_credentials ) { { } }
it 'does not generate a signed url for head' do
expect_any_instance_of ( Fog :: AWS :: Storage :: Files ) . not_to receive ( :head_url )
subject
end
2021-04-29 21:17:54 +05:30
context 'with a non existing maven path' do
let ( :path ) { 'foo/bar/1.2.3' }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , instance_level ? :forbidden : :redirect
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
end
2023-07-09 08:55:56 +05:30
shared_examples 'allowing the download' do
it 'allows download' do
subject
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'application/octet-stream' )
end
end
shared_examples 'not allowing the download with' do | not_found_response |
it 'does not allow the download' do
subject
expect ( response ) . to have_gitlab_http_status ( not_found_response )
end
end
shared_examples 'downloads with a personal access token' do | not_found_response |
where ( :valid , :sent_using ) do
true | :custom_header
false | :custom_header
true | :basic_auth
false | :basic_auth
end
with_them do
let ( :token ) { valid ? personal_access_token . token : 'not_valid' }
let ( :headers ) do
case sent_using
when :custom_header
{ 'Private-Token' = > token }
when :basic_auth
basic_auth_header ( user . username , token )
end
end
2021-01-29 00:20:46 +05:30
subject do
download_file (
2021-04-29 21:17:54 +05:30
file_name : package_file . file_name ,
2023-07-09 08:55:56 +05:30
request_headers : headers
2021-01-29 00:20:46 +05:30
)
end
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
if params [ :valid ]
it_behaves_like 'allowing the download'
else
expected_status_code = not_found_response
# invalid PAT values sent through headers are validated.
# Invalid values will trigger an :unauthorized response (and not set current_user to nil)
expected_status_code = :unauthorized if params [ :sent_using ] == :custom_header && ! params [ :valid ]
it_behaves_like 'not allowing the download with' , expected_status_code
end
end
end
2021-01-29 00:20:46 +05:30
2023-07-09 08:55:56 +05:30
shared_examples 'downloads with a deploy token' do | not_found_response |
where ( :valid , :sent_using ) do
true | :custom_header
false | :custom_header
true | :basic_auth
false | :basic_auth
end
with_them do
let ( :token ) { valid ? deploy_token . token : 'not_valid' }
let ( :headers ) do
case sent_using
when :custom_header
{ Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > token }
when :basic_auth
basic_auth_header ( deploy_token . username , token )
end
2021-01-29 00:20:46 +05:30
end
2023-07-09 08:55:56 +05:30
subject do
download_file (
file_name : package_file . file_name ,
request_headers : headers
)
end
2021-01-29 00:20:46 +05:30
2023-07-09 08:55:56 +05:30
if params [ :valid ]
it_behaves_like 'allowing the download'
2021-01-29 00:20:46 +05:30
2023-07-09 08:55:56 +05:30
context 'with only write_package_registry scope' do
it_behaves_like 'allowing the download' do
before do
deploy_token . update! ( read_package_registry : false )
end
end
end
else
it_behaves_like 'not allowing the download with' , not_found_response
2021-01-29 00:20:46 +05:30
end
2020-07-28 23:09:34 +05:30
end
end
shared_examples 'downloads with a job token' do
2023-07-09 08:55:56 +05:30
where ( :valid , :sent_using ) do
true | :custom_params
false | :custom_params
true | :basic_auth
false | :basic_auth
end
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
with_them do
let ( :token ) { valid ? job . token : 'not_valid' }
let ( :headers ) { basic_auth_header ( :: Gitlab :: Auth :: CI_JOB_USER , token ) }
let ( :params ) { { job_token : token } }
subject do
case sent_using
when :custom_params
download_file ( file_name : package_file . file_name , params : params )
when :basic_auth
download_file ( file_name : package_file . file_name , request_headers : headers )
end
2020-09-03 11:15:55 +05:30
end
2023-07-09 08:55:56 +05:30
context 'with a running job' do
if params [ :valid ]
it_behaves_like 'allowing the download'
else
it_behaves_like 'not allowing the download with' , :unauthorized
end
2020-09-03 11:15:55 +05:30
end
2023-07-09 08:55:56 +05:30
context 'with a finished job' do
before do
job . update! ( status : :failed )
end
2020-09-03 11:15:55 +05:30
2023-07-09 08:55:56 +05:30
it_behaves_like 'not allowing the download with' , :unauthorized
2020-09-03 11:15:55 +05:30
end
2020-07-28 23:09:34 +05:30
end
end
2023-07-09 08:55:56 +05:30
shared_examples 'downloads with different tokens' do | not_found_response |
it_behaves_like 'downloads with a personal access token' , not_found_response
it_behaves_like 'downloads with a deploy token' , not_found_response
it_behaves_like 'downloads with a job token'
end
2021-10-27 15:23:28 +05:30
shared_examples 'successfully returning the file' do
it 'returns the file' , :aggregate_failures do
subject
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'application/octet-stream' )
end
end
2022-08-13 15:12:31 +05:30
shared_examples 'file download in FIPS mode' do
context 'in FIPS mode' , :fips_mode do
it_behaves_like 'successfully returning the file'
it 'rejects the request for an md5 file' do
download_file ( file_name : package_file . file_name + '.md5' )
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
end
end
end
2022-10-11 01:57:18 +05:30
shared_examples 'forwarding package requests' do
context 'request forwarding' do
include_context 'dependency proxy helpers context'
subject { download_file ( file_name : package_name ) }
shared_examples 'redirecting the request' do
it_behaves_like 'returning response status' , :redirect
end
shared_examples 'package not found' do
it_behaves_like 'returning response status' , :not_found
end
where ( :forward , :package_in_project , :shared_examples_name ) do
true | true | 'successfully returning the file'
true | false | 'redirecting the request'
false | true | 'successfully returning the file'
false | false | 'package not found'
end
with_them do
let ( :package_name ) { package_in_project ? package_file . file_name : 'foo' }
before do
2022-11-25 23:54:43 +05:30
allow_fetch_cascade_application_setting ( attribute : 'maven_package_requests_forwarding' , return_value : forward )
2022-10-11 01:57:18 +05:30
end
it_behaves_like params [ :shared_examples_name ]
end
context 'with maven_central_request_forwarding disabled' do
where ( :forward , :package_in_project , :shared_examples_name ) do
true | true | 'successfully returning the file'
true | false | 'package not found'
false | true | 'successfully returning the file'
false | false | 'package not found'
end
with_them do
let ( :package_name ) { package_in_project ? package_file . file_name : 'foo' }
before do
stub_feature_flags ( maven_central_request_forwarding : false )
2022-11-25 23:54:43 +05:30
allow_fetch_cascade_application_setting ( attribute : 'maven_package_requests_forwarding' , return_value : forward )
2022-10-11 01:57:18 +05:30
end
it_behaves_like params [ :shared_examples_name ]
end
end
end
end
2020-07-28 23:09:34 +05:30
describe 'GET /api/v4/packages/maven/*path/:file_name' do
2021-09-04 01:27:46 +05:30
context 'a public project' do
2023-05-27 22:25:52 +05:30
let ( :snowplow_gitlab_standard_context ) { { project : project , namespace : project . namespace , property : 'i_package_maven_user' } }
2021-09-04 01:27:46 +05:30
subject { download_file ( file_name : package_file . file_name ) }
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
shared_examples 'getting a file' do
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2022-08-13 15:12:31 +05:30
it_behaves_like 'file download in FIPS mode'
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
it 'returns sha1 of the file' do
download_file ( file_name : package_file . file_name + '.sha1' )
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'text/plain' )
expect ( response . body ) . to eq ( package_file . file_sha1 )
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
context 'with a non existing maven path' do
subject { download_file ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :forbidden
end
it 'returns not found when a package is not found' do
finder = double ( 'finder' , execute : nil )
expect ( :: Packages :: Maven :: PackageFinder ) . to receive ( :new ) . and_return ( finder )
subject
expect ( response ) . to have_gitlab_http_status ( :not_found )
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
2021-09-04 01:27:46 +05:30
it_behaves_like 'handling groups, subgroups and user namespaces for' , 'getting a file'
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'internal project' do
before do
project . team . truncate
project . update! ( visibility_level : Gitlab :: VisibilityLevel :: INTERNAL )
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject { download_file_with_token ( file_name : package_file . file_name ) }
shared_examples 'getting a file' do
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
it 'denies download when no private token' do
download_file ( file_name : package_file . file_name )
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
it_behaves_like 'downloads with different tokens' , :unauthorized
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2020-07-28 23:09:34 +05:30
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :forbidden
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
2022-10-11 01:57:18 +05:30
it_behaves_like 'handling groups, subgroups and user namespaces for' , 'getting a file' , visibilities : { public : :redirect , internal : :not_found }
2021-09-04 01:27:46 +05:30
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'private project' do
subject { download_file_with_token ( file_name : package_file . file_name ) }
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
before do
project . update! ( visibility_level : Gitlab :: VisibilityLevel :: PRIVATE )
end
shared_examples 'getting a file' do
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
it 'denies download when not enough permissions' do
2021-09-04 01:27:46 +05:30
unless project . root_namespace == user . namespace
project . add_guest ( user )
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
it 'denies download when no private token' do
download_file ( file_name : package_file . file_name )
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2021-04-29 21:17:54 +05:30
end
2020-08-19 02:56:42 +05:30
2023-07-09 08:55:56 +05:30
it_behaves_like 'downloads with different tokens' , :unauthorized
2020-08-19 02:56:42 +05:30
2021-04-29 21:17:54 +05:30
it 'does not allow download by a unauthorized deploy token with same id as a user with access' do
unauthorized_deploy_token = create ( :deploy_token , read_package_registry : true , write_package_registry : true )
2020-08-19 02:56:42 +05:30
2021-04-29 21:17:54 +05:30
another_user = create ( :user )
project . add_developer ( another_user )
# We force the id of the deploy token and the user to be the same
unauthorized_deploy_token . update! ( id : another_user . id )
2020-08-19 02:56:42 +05:30
2021-04-29 21:17:54 +05:30
download_file (
file_name : package_file . file_name ,
request_headers : { Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > unauthorized_deploy_token . token }
)
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :forbidden
2021-04-29 21:17:54 +05:30
end
2020-08-19 02:56:42 +05:30
end
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
it_behaves_like 'handling groups, subgroups and user namespaces for' , 'getting a file' , visibilities : { public : :redirect , internal : :not_found , private : :not_found }
2021-04-29 21:17:54 +05:30
end
2021-09-04 01:27:46 +05:30
context 'project name is different from a package name' do
it 'rejects request' do
2023-07-09 08:55:56 +05:30
download_file ( file_name : package_file . file_name , path : " wrong_name/ #{ package . version } " )
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2020-07-28 23:09:34 +05:30
end
end
2021-04-29 21:17:54 +05:30
def download_file ( file_name : , params : { } , request_headers : headers , path : maven_metadatum . path )
get api ( " /packages/maven/ #{ path } / #{ file_name } " ) , params : params , headers : request_headers
2020-07-28 23:09:34 +05:30
end
2021-04-29 21:17:54 +05:30
def download_file_with_token ( file_name : , params : { } , request_headers : headers_with_token , path : maven_metadatum . path )
download_file ( file_name : file_name , params : params , request_headers : request_headers , path : path )
2020-07-28 23:09:34 +05:30
end
end
describe 'HEAD /api/v4/packages/maven/*path/:file_name' do
2021-04-29 21:17:54 +05:30
let ( :path ) { package . maven_metadatum . path }
let ( :url ) { " /packages/maven/ #{ path } / #{ package_file . file_name } " }
2021-09-04 01:27:46 +05:30
shared_examples 'heading a file' do
it_behaves_like 'processing HEAD requests' , instance_level : true
end
2021-04-29 21:17:54 +05:30
2022-11-25 23:54:43 +05:30
it_behaves_like 'handling groups, subgroups and user namespaces for' , 'heading a file'
2020-07-28 23:09:34 +05:30
end
describe 'GET /api/v4/groups/:id/-/packages/maven/*path/:file_name' do
before do
project . team . truncate
group . add_developer ( user )
end
2022-10-11 01:57:18 +05:30
it_behaves_like 'forwarding package requests'
2021-09-04 01:27:46 +05:30
context 'a public project' do
2023-05-27 22:25:52 +05:30
let ( :snowplow_gitlab_standard_context ) { { project : project , namespace : project . namespace , property : 'i_package_maven_user' } }
2021-09-04 01:27:46 +05:30
subject { download_file ( file_name : package_file . file_name ) }
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
shared_examples 'getting a file for a group' do
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2022-08-13 15:12:31 +05:30
it_behaves_like 'file download in FIPS mode'
2021-04-29 21:17:54 +05:30
it 'returns sha1 of the file' do
download_file ( file_name : package_file . file_name + '.sha1' )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'text/plain' )
expect ( response . body ) . to eq ( package_file . file_sha1 )
end
context 'with a non existing maven path' do
subject { download_file ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
2021-09-04 01:27:46 +05:30
it_behaves_like 'handling groups and subgroups for' , 'getting a file for a group'
end
context 'internal project' do
before do
2022-03-02 08:16:31 +05:30
group . member ( user ) . destroy!
2021-09-04 01:27:46 +05:30
project . update! ( visibility_level : Gitlab :: VisibilityLevel :: INTERNAL )
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject { download_file_with_token ( file_name : package_file . file_name ) }
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
shared_examples 'getting a file for a group' do | not_found_response |
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
it 'forwards download when no private token' do
2021-04-29 21:17:54 +05:30
download_file ( file_name : package_file . file_name )
2022-10-11 01:57:18 +05:30
expect ( response ) . to have_gitlab_http_status ( not_found_response )
2021-04-29 21:17:54 +05:30
end
2023-07-09 08:55:56 +05:30
it_behaves_like 'downloads with different tokens' , not_found_response
2021-04-29 21:17:54 +05:30
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
2023-07-09 08:55:56 +05:30
it_behaves_like 'handling groups and subgroups for' , 'getting a file for a group' , visibilities : { internal : :unauthorized , public : :redirect }
2021-09-04 01:27:46 +05:30
end
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
context 'private project' do
before do
project . update! ( visibility_level : Gitlab :: VisibilityLevel :: PRIVATE )
end
subject { download_file_with_token ( file_name : package_file . file_name ) }
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
shared_examples 'getting a file for a group' do | not_found_response |
2021-04-29 21:17:54 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2021-04-29 21:17:54 +05:30
it 'denies download when not enough permissions' do
group . add_guest ( user )
subject
2022-10-11 01:57:18 +05:30
expect ( response ) . to have_gitlab_http_status ( :redirect )
2021-04-29 21:17:54 +05:30
end
it 'denies download when no private token' do
download_file ( file_name : package_file . file_name )
2022-10-11 01:57:18 +05:30
expect ( response ) . to have_gitlab_http_status ( not_found_response )
2021-04-29 21:17:54 +05:30
end
2023-07-09 08:55:56 +05:30
it_behaves_like 'downloads with different tokens' , not_found_response
2021-04-29 21:17:54 +05:30
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-04-29 21:17:54 +05:30
end
context 'with group deploy token' do
subject { download_file_with_token ( file_name : package_file . file_name , request_headers : group_deploy_token_headers ) }
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2021-04-29 21:17:54 +05:30
it 'returns the file with only write_package_registry scope' do
deploy_token_for_group . update! ( read_package_registry : false )
subject
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'application/octet-stream' )
end
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' , request_headers : group_deploy_token_headers ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-04-29 21:17:54 +05:30
end
end
2021-09-04 01:27:46 +05:30
end
2021-04-29 21:17:54 +05:30
2023-07-09 08:55:56 +05:30
it_behaves_like 'handling groups and subgroups for' , 'getting a file for a group' , visibilities : { private : :unauthorized , internal : :unauthorized , public : :redirect }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
context 'with a reporter from a subgroup accessing the root group' do
let_it_be ( :root_group ) { create ( :group , :private ) }
let_it_be ( :group ) { create ( :group , :private , parent : root_group ) }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
subject { download_file_with_token ( file_name : package_file . file_name , request_headers : headers_with_token , group_id : root_group . id ) }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
before do
project . update! ( namespace : group )
group . add_reporter ( user )
end
2021-04-29 21:17:54 +05:30
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' , request_headers : headers_with_token , group_id : root_group . id ) }
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
end
2021-09-04 01:27:46 +05:30
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'maven metadata file' do
let_it_be ( :sub_group1 ) { create ( :group , parent : group ) }
let_it_be ( :sub_group2 ) { create ( :group , parent : group ) }
let_it_be ( :project1 ) { create ( :project , :private , group : sub_group1 ) }
let_it_be ( :project2 ) { create ( :project , :private , group : sub_group2 ) }
let_it_be ( :project3 ) { create ( :project , :private , group : sub_group1 ) }
let_it_be ( :package_name ) { 'foo' }
let_it_be ( :package1 ) { create ( :maven_package , project : project1 , name : package_name , version : nil ) }
let_it_be ( :package_file1 ) { create ( :package_file , :xml , package : package1 , file_name : 'maven-metadata.xml' ) }
let_it_be ( :package2 ) { create ( :maven_package , project : project2 , name : package_name , version : nil ) }
let_it_be ( :package_file2 ) { create ( :package_file , :xml , package : package2 , file_name : 'maven-metadata.xml' ) }
let_it_be ( :package3 ) { create ( :maven_package , project : project3 , name : package_name , version : nil ) }
let_it_be ( :package_file3 ) { create ( :package_file , :xml , package : package3 , file_name : 'maven-metadata.xml' ) }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
let ( :maven_metadatum ) { package3 . maven_metadatum }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
subject { download_file_with_token ( file_name : package_file3 . file_name ) }
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
before do
sub_group1 . add_developer ( user )
sub_group2 . add_developer ( user )
# the package with the most recently published file should be returned
create ( :package_file , :xml , package : package2 )
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'in multiple versionless packages' do
it 'downloads the file' do
expect ( :: Packages :: PackageFileFinder )
. to receive ( :new ) . with ( package2 , 'maven-metadata.xml' ) . and_call_original
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject
2021-04-29 21:17:54 +05:30
end
2021-09-04 01:27:46 +05:30
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'in multiple snapshot packages' do
before do
version = '1.0.0-SNAPSHOT'
[ package1 , package2 , package3 ] . each do | pkg |
pkg . update! ( version : version )
2021-04-29 21:17:54 +05:30
2021-09-04 01:27:46 +05:30
pkg . maven_metadatum . update! ( path : " #{ pkg . name } / #{ pkg . version } " )
2021-04-29 21:17:54 +05:30
end
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
it 'downloads the file' do
expect ( :: Packages :: PackageFileFinder )
. to receive ( :new ) . with ( package3 , 'maven-metadata.xml' ) . and_call_original
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject
end
2020-07-28 23:09:34 +05:30
end
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
def download_file ( file_name : , params : { } , request_headers : headers , path : maven_metadatum . path , group_id : group . id )
get api ( " /groups/ #{ group_id } /-/packages/maven/ #{ path } / #{ file_name } " ) , params : params , headers : request_headers
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
def download_file_with_token ( file_name : , params : { } , request_headers : headers_with_token , path : maven_metadatum . path , group_id : group . id )
download_file ( file_name : file_name , params : params , request_headers : request_headers , path : path , group_id : group_id )
end
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
describe 'HEAD /api/v4/groups/:id/-/packages/maven/*path/:file_name' do
let ( :path ) { package . maven_metadatum . path }
let ( :url ) { " /groups/ #{ group . id } /-/packages/maven/ #{ path } / #{ package_file . file_name } " }
2022-11-25 23:54:43 +05:30
it_behaves_like 'handling groups and subgroups for' , 'processing HEAD requests'
2021-04-29 21:17:54 +05:30
end
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do
2021-09-04 01:27:46 +05:30
context 'a public project' do
2023-05-27 22:25:52 +05:30
let ( :snowplow_gitlab_standard_context ) { { project : project , namespace : project . namespace , property : 'i_package_maven_user' } }
2021-09-04 01:27:46 +05:30
subject { download_file ( file_name : package_file . file_name ) }
2021-01-29 00:20:46 +05:30
2021-09-04 01:27:46 +05:30
it_behaves_like 'tracking the file download event'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2022-08-13 15:12:31 +05:30
it_behaves_like 'file download in FIPS mode'
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
%w[ sha1 md5 ] . each do | format |
it " returns #{ format } of the file " do
download_file ( file_name : package_file . file_name + " . #{ format } " )
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( 'text/plain' )
expect ( response . body ) . to eq ( package_file . send ( " file_ #{ format } " . to_sym ) )
end
2021-09-04 01:27:46 +05:30
end
2021-01-29 00:20:46 +05:30
2021-10-27 15:23:28 +05:30
context 'when the repository is disabled' do
before do
project . project_feature . update! (
# Disable merge_requests and builds as well, since merge_requests and
# builds cannot have higher visibility than repository.
merge_requests_access_level : ProjectFeature :: DISABLED ,
builds_access_level : ProjectFeature :: DISABLED ,
repository_access_level : ProjectFeature :: DISABLED )
end
it_behaves_like 'successfully returning the file'
end
2021-09-04 01:27:46 +05:30
context 'with a non existing maven path' do
subject { download_file ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2021-04-29 21:17:54 +05:30
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-09-04 01:27:46 +05:30
end
end
2021-01-29 00:20:46 +05:30
2021-09-04 01:27:46 +05:30
context 'private project' do
before do
project . update! ( visibility_level : Gitlab :: VisibilityLevel :: PRIVATE )
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject { download_file_with_token ( file_name : package_file . file_name ) }
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
it_behaves_like 'tracking the file download event'
2022-10-11 01:57:18 +05:30
it_behaves_like 'bumping the package last downloaded at field'
2021-10-27 15:23:28 +05:30
it_behaves_like 'successfully returning the file'
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
it 'denies download when not enough permissions' do
project . add_guest ( user )
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
subject
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
it 'denies download when no private token' do
download_file ( file_name : package_file . file_name )
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2020-07-28 23:09:34 +05:30
end
2023-01-13 00:05:48 +05:30
context 'with access to package registry for everyone' do
subject { download_file ( file_name : package_file . file_name ) }
before do
project . project_feature . update! ( package_registry_access_level : ProjectFeature :: PUBLIC )
end
it_behaves_like 'successfully returning the file'
end
2023-07-09 08:55:56 +05:30
it_behaves_like 'downloads with different tokens' , :unauthorized
2020-07-28 23:09:34 +05:30
2021-09-04 01:27:46 +05:30
context 'with a non existing maven path' do
subject { download_file_with_token ( file_name : package_file . file_name , path : 'foo/bar/1.2.3' ) }
2020-07-28 23:09:34 +05:30
2022-10-11 01:57:18 +05:30
it_behaves_like 'returning response status' , :redirect
2021-09-04 01:27:46 +05:30
end
2020-07-28 23:09:34 +05:30
end
2022-10-11 01:57:18 +05:30
it_behaves_like 'forwarding package requests'
2021-04-29 21:17:54 +05:30
def download_file ( file_name : , params : { } , request_headers : headers , path : maven_metadatum . path )
2020-07-28 23:09:34 +05:30
get api ( " /projects/ #{ project . id } /packages/maven/ " \
2021-04-29 21:17:54 +05:30
" #{ path } / #{ file_name } " ) , params : params , headers : request_headers
2020-07-28 23:09:34 +05:30
end
2021-04-29 21:17:54 +05:30
def download_file_with_token ( file_name : , params : { } , request_headers : headers_with_token , path : maven_metadatum . path )
download_file ( file_name : file_name , params : params , request_headers : request_headers , path : path )
2020-07-28 23:09:34 +05:30
end
end
describe 'HEAD /api/v4/projects/:id/packages/maven/*path/:file_name' do
2021-04-29 21:17:54 +05:30
let ( :path ) { package . maven_metadatum . path }
let ( :url ) { " /projects/ #{ project . id } /packages/maven/ #{ path } / #{ package_file . file_name } " }
2020-07-28 23:09:34 +05:30
2022-11-25 23:54:43 +05:30
it_behaves_like 'processing HEAD requests'
2020-07-28 23:09:34 +05:30
end
describe 'PUT /api/v4/projects/:id/packages/maven/*path/:file_name/authorize' do
it 'rejects a malicious request' do
2021-04-29 21:17:54 +05:30
put api ( " /projects/ #{ project . id } /packages/maven/com/example/my-app/ #{ version } /%2e%2e%2F.ssh%2Fauthorized_keys/authorize " ) , headers : headers_with_token
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
it 'authorizes posting package with a valid token' do
authorize_upload_with_token
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response . media_type ) . to eq ( Gitlab :: Workhorse :: INTERNAL_API_CONTENT_TYPE )
expect ( json_response [ 'TempPath' ] ) . not_to be_nil
end
it 'rejects request without a valid token' do
headers_with_token [ 'Private-Token' ] = 'foo'
authorize_upload_with_token
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
it 'rejects request without a valid permission' do
project . add_guest ( user )
authorize_upload_with_token
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
it 'rejects requests that did not go through gitlab-workhorse' do
headers . delete ( Gitlab :: Workhorse :: INTERNAL_API_REQUEST_HEADER )
authorize_upload_with_token
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
it 'authorizes upload with job token' do
authorize_upload ( job_token : job . token )
expect ( response ) . to have_gitlab_http_status ( :ok )
end
it 'authorizes upload with deploy token' do
authorize_upload ( { } , headers_with_deploy_token )
expect ( response ) . to have_gitlab_http_status ( :ok )
end
2020-08-19 02:56:42 +05:30
it 'rejects requests by a unauthorized deploy token with same id as a user with access' do
unauthorized_deploy_token = create ( :deploy_token , read_package_registry : true , write_package_registry : true )
another_user = create ( :user )
project . add_developer ( another_user )
# We force the id of the deploy token and the user to be the same
unauthorized_deploy_token . update! ( id : another_user . id )
authorize_upload ( { } , headers . merge ( Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > unauthorized_deploy_token . token ) )
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
2020-07-28 23:09:34 +05:30
def authorize_upload ( params = { } , request_headers = headers )
put api ( " /projects/ #{ project . id } /packages/maven/com/example/my-app/ #{ version } /maven-metadata.xml/authorize " ) , params : params , headers : request_headers
end
def authorize_upload_with_token ( params = { } , request_headers = headers_with_token )
authorize_upload ( params , request_headers )
end
end
describe 'PUT /api/v4/projects/:id/packages/maven/*path/:file_name' do
let ( :send_rewritten_field ) { true }
let ( :file_upload ) { fixture_file_upload ( 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.jar' ) }
before do
# by configuring this path we allow to pass temp file from any path
allow ( Packages :: PackageFileUploader ) . to receive ( :workhorse_upload_path ) . and_return ( '/' )
end
it 'rejects requests without a file from workhorse' do
upload_file_with_token
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
it 'rejects request without a token' do
upload_file
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
context 'without workhorse rewritten field' do
let ( :send_rewritten_field ) { false }
it 'rejects the request' do
upload_file_with_token
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
end
context 'when params from workhorse are correct' do
let ( :params ) { { file : file_upload } }
2021-11-18 22:05:49 +05:30
subject { upload_file_with_token ( params : params ) }
2022-08-13 15:12:31 +05:30
context 'FIPS mode' , :fips_mode do
it_behaves_like 'package workhorse uploads'
it 'rejects the request for md5 file' do
upload_file_with_token ( params : params , file_extension : 'jar.md5' )
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
end
end
2020-11-24 15:15:51 +05:30
context 'file size is too large' do
it 'rejects the request' do
allow_next_instance_of ( UploadedFile ) do | uploaded_file |
allow ( uploaded_file ) . to receive ( :size ) . and_return ( project . actual_limits . maven_max_file_size + 1 )
end
2021-01-03 14:25:43 +05:30
upload_file_with_token ( params : params )
2020-11-24 15:15:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
end
2020-07-28 23:09:34 +05:30
it 'rejects a malicious request' do
put api ( " /projects/ #{ project . id } /packages/maven/com/example/my-app/ #{ version } /%2e%2e%2f.ssh%2fauthorized_keys " ) , params : params , headers : headers_with_token
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
2021-11-18 22:05:49 +05:30
it_behaves_like 'package workhorse uploads'
2020-07-28 23:09:34 +05:30
context 'event tracking' do
2021-01-03 14:25:43 +05:30
it_behaves_like 'a package tracking event' , described_class . name , 'push_package'
2021-11-18 22:05:49 +05:30
context 'when the package file fails to be created' do
before do
allow_next_instance_of ( :: Packages :: CreatePackageFileService ) do | create_package_file_service |
allow ( create_package_file_service ) . to receive ( :execute ) . and_raise ( StandardError )
end
end
it_behaves_like 'not a package tracking event'
end
2020-07-28 23:09:34 +05:30
end
it 'creates package and stores package file' do
2023-06-20 00:43:36 +05:30
expect_use_primary
2021-01-03 14:25:43 +05:30
expect { upload_file_with_token ( params : params ) } . to change { project . packages . count } . by ( 1 )
2020-07-28 23:09:34 +05:30
. and change { Packages :: Maven :: Metadatum . count } . by ( 1 )
. and change { Packages :: PackageFile . count } . by ( 1 )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( jar_file . file_name ) . to eq ( file_upload . original_filename )
end
2020-09-03 11:15:55 +05:30
it 'allows upload with running job token' do
2021-01-03 14:25:43 +05:30
upload_file ( params : params . merge ( job_token : job . token ) )
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-01-29 00:20:46 +05:30
expect ( project . reload . packages . last . original_build_info . pipeline ) . to eq job . pipeline
2020-07-28 23:09:34 +05:30
end
2020-09-03 11:15:55 +05:30
it 'rejects upload without running job token' do
job . update! ( status : :failed )
2021-01-03 14:25:43 +05:30
upload_file ( params : params . merge ( job_token : job . token ) )
2020-09-03 11:15:55 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
2020-07-28 23:09:34 +05:30
it 'allows upload with deploy token' do
2021-01-03 14:25:43 +05:30
upload_file ( params : params , request_headers : headers_with_deploy_token )
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
end
2020-08-19 02:56:42 +05:30
it 'rejects uploads by a unauthorized deploy token with same id as a user with access' do
unauthorized_deploy_token = create ( :deploy_token , read_package_registry : true , write_package_registry : true )
another_user = create ( :user )
project . add_developer ( another_user )
# We force the id of the deploy token and the user to be the same
unauthorized_deploy_token . update! ( id : another_user . id )
2021-01-03 14:25:43 +05:30
upload_file (
params : params ,
request_headers : headers . merge ( Gitlab :: Auth :: AuthFinders :: DEPLOY_TOKEN_HEADER = > unauthorized_deploy_token . token )
)
2020-08-19 02:56:42 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
2023-05-27 22:25:52 +05:30
context 'file name is too long' do
let ( :file_name ) { 'a' * ( Packages :: Maven :: FindOrCreatePackageService :: MAX_FILE_NAME_LENGTH + 1 ) }
it 'rejects request' do
expect { upload_file_with_token ( params : params , file_name : file_name ) } . not_to change { project . packages . count }
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] ) . to include ( 'File name is too long' )
end
end
2020-07-28 23:09:34 +05:30
context 'version is not correct' do
let ( :version ) { '$%123' }
it 'rejects request' do
2021-01-03 14:25:43 +05:30
expect { upload_file_with_token ( params : params ) } . not_to change { project . packages . count }
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] ) . to include ( 'Validation failed' )
end
end
2021-01-03 14:25:43 +05:30
2021-03-08 18:12:59 +05:30
context 'when package duplicates are not allowed' do
let ( :package_name ) { package . name }
let ( :version ) { package . version }
before do
package_settings . update! ( maven_duplicates_allowed : false )
end
2023-05-27 22:25:52 +05:30
shared_examples 'storing the package file' do | file_name : 'my-app-1.0-20180724.124855-1' |
2021-03-08 18:12:59 +05:30
it 'stores the file' , :aggregate_failures do
2023-05-27 22:25:52 +05:30
expect { upload_file_with_token ( params : params , file_name : file_name ) } . to change { package . package_files . count } . by ( 1 )
2021-03-08 18:12:59 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( jar_file . file_name ) . to eq ( file_upload . original_filename )
end
end
it 'rejects the request' , :aggregate_failures do
expect { upload_file_with_token ( params : params ) } . not_to change { package . package_files . count }
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] ) . to include ( 'Duplicate package is not allowed' )
end
2021-03-11 19:13:27 +05:30
context 'when uploading to the versionless package which contains metadata about all versions' do
let ( :version ) { nil }
let ( :param_path ) { package_name }
let! ( :package ) { create ( :maven_package , project : project , version : version , name : project . full_path ) }
it_behaves_like 'storing the package file'
end
2021-03-08 18:12:59 +05:30
context 'when uploading different non-duplicate files to the same package' do
let! ( :package ) { create ( :maven_package , project : project , name : project . full_path ) }
before do
package_file = package . package_files . find_by ( file_name : 'my-app-1.0-20180724.124855-1.jar' )
package_file . destroy!
end
it_behaves_like 'storing the package file'
end
context 'when the package name matches the exception regex' do
before do
package_settings . update! ( maven_duplicate_exception_regex : '.*' )
end
it_behaves_like 'storing the package file'
end
2023-05-27 22:25:52 +05:30
context 'when uploading a similar package file name with a classifier' do
it_behaves_like 'storing the package file' , file_name : 'my-app-1.0-20180724.124855-1-javadoc'
end
2021-03-08 18:12:59 +05:30
end
2021-01-03 14:25:43 +05:30
context 'for sha1 file' do
let ( :dummy_package ) { double ( Packages :: Package ) }
2022-08-27 11:52:29 +05:30
let ( :file_upload ) { fixture_file_upload ( 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.pom.sha1' ) }
let ( :stored_sha1 ) { File . read ( file_upload . path ) }
2021-01-03 14:25:43 +05:30
2022-08-27 11:52:29 +05:30
subject ( :upload ) { upload_file_with_token ( params : params , file_extension : 'pom.sha1' ) }
before do
2021-01-03 14:25:43 +05:30
# The sha verification done by the maven api is between:
# - the sha256 set by workhorse helpers
# - the sha256 of the sha1 of the uploaded package file
# We're going to send `file_upload` for the sha1 and stub the sha1 of the package file so that
# both sha256 being the same
2022-08-27 11:52:29 +05:30
allow ( :: Packages :: PackageFileFinder ) . to receive ( :new ) . and_return ( double ( execute! : dummy_package ) )
allow ( dummy_package ) . to receive ( :file_sha1 ) . and_return ( stored_sha1 )
end
2021-01-03 14:25:43 +05:30
2022-08-27 11:52:29 +05:30
it 'returns no content' do
2023-06-20 00:43:36 +05:30
expect_use_primary
2022-08-27 11:52:29 +05:30
upload
2021-01-03 14:25:43 +05:30
expect ( response ) . to have_gitlab_http_status ( :no_content )
end
2022-08-27 11:52:29 +05:30
context 'when the stored sha1 is not the same' do
let ( :sent_sha1 ) { File . read ( file_upload . path ) }
let ( :stored_sha1 ) { 'wrong sha1' }
it 'logs an error and returns conflict' do
expect ( Gitlab :: ErrorTracking ) . to receive ( :log_exception ) . with (
instance_of ( ArgumentError ) ,
message : 'maven package file sha1 conflict' ,
stored_sha1 : stored_sha1 ,
received_sha256 : Digest :: SHA256 . hexdigest ( sent_sha1 ) ,
sha256_hexdigest_of_stored_sha1 : Digest :: SHA256 . hexdigest ( stored_sha1 )
)
upload
expect ( response ) . to have_gitlab_http_status ( :conflict )
end
end
2021-01-03 14:25:43 +05:30
end
context 'for md5 file' do
2022-08-13 15:12:31 +05:30
subject { upload_file_with_token ( params : params , file_extension : 'jar.md5' ) }
2021-01-03 14:25:43 +05:30
it 'returns an empty body' do
2023-06-20 00:43:36 +05:30
expect_use_primary
2022-08-13 15:12:31 +05:30
subject
2021-01-03 14:25:43 +05:30
expect ( response . body ) . to eq ( '' )
expect ( response ) . to have_gitlab_http_status ( :ok )
end
2022-08-13 15:12:31 +05:30
context 'with FIPS mode enabled' , :fips_mode do
it 'rejects the request' do
subject
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
end
end
2021-01-03 14:25:43 +05:30
end
2023-06-20 00:43:36 +05:30
context 'reading fingerprints from UploadedFile instance' do
let ( :file ) { Packages :: Package . last . package_files . with_format ( '%.jar' ) . last }
subject { upload_file_with_token ( params : params ) }
before do
allow_next_instance_of ( UploadedFile ) do | uploaded_file |
allow ( uploaded_file ) . to receive ( :size ) . and_return ( 123 )
allow ( uploaded_file ) . to receive ( :sha1 ) . and_return ( 'sha1' )
allow ( uploaded_file ) . to receive ( :md5 ) . and_return ( 'md5' )
end
end
2023-07-09 08:55:56 +05:30
it 'reads size, sha1 and md5 fingerprints from uploaded_file instance' do
subject
2023-06-20 00:43:36 +05:30
2023-07-09 08:55:56 +05:30
expect ( file . size ) . to eq ( 123 )
expect ( file . file_sha1 ) . to eq ( 'sha1' )
expect ( file . file_md5 ) . to eq ( 'md5' )
2023-06-20 00:43:36 +05:30
end
end
def expect_use_primary
lb_session = :: Gitlab :: Database :: LoadBalancing :: Session . current
expect ( lb_session ) . to receive ( :use_primary ) . and_call_original
allow ( :: Gitlab :: Database :: LoadBalancing :: Session ) . to receive ( :current ) . and_return ( lb_session )
end
2020-07-28 23:09:34 +05:30
end
2023-05-27 22:25:52 +05:30
def upload_file ( params : { } , request_headers : headers , file_extension : 'jar' , file_name : 'my-app-1.0-20180724.124855-1' )
url = " /projects/ #{ project . id } /packages/maven/ #{ param_path } / #{ file_name } . #{ file_extension } "
2020-07-28 23:09:34 +05:30
workhorse_finalize (
api ( url ) ,
method : :put ,
file_key : :file ,
params : params ,
headers : request_headers ,
send_rewritten_field : send_rewritten_field
)
end
2023-05-27 22:25:52 +05:30
def upload_file_with_token ( params : { } , request_headers : headers_with_token , file_extension : 'jar' , file_name : 'my-app-1.0-20180724.124855-1' )
upload_file ( params : params , request_headers : request_headers , file_name : file_name , file_extension : file_extension )
2020-07-28 23:09:34 +05:30
end
end
2021-09-04 01:27:46 +05:30
def move_project_to_namespace ( namespace )
project . update! ( namespace : namespace )
package . update! ( name : project . full_path )
maven_metadatum . update! ( path : " #{ package . name } / #{ package . version } " )
end
2020-07-28 23:09:34 +05:30
end