Commit 37a34673 authored by David Fernandez's avatar David Fernandez Committed by Stan Hu

Check maven path for maven file API endpoints [RUN ALL RSPEC] [RUN AS-IF-FOSS]

parent 6d15237d
...@@ -19,6 +19,7 @@ class Packages::Maven::Metadatum < ApplicationRecord ...@@ -19,6 +19,7 @@ class Packages::Maven::Metadatum < ApplicationRecord
validate :maven_package_type validate :maven_package_type
scope :for_package_ids, -> (package_ids) { where(package_id: package_ids) } scope :for_package_ids, -> (package_ids) { where(package_id: package_ids) }
scope :with_path, ->(path) { where(path: path) }
scope :order_created, -> { reorder('created_at ASC') } scope :order_created, -> { reorder('created_at ASC') }
def self.pluck_app_name def self.pluck_app_name
......
---
title: Add index for the path column on the packages_maven_metadata table
merge_request: 59241
author:
type: performance
---
name: check_maven_path_first
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59241
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327487
milestone: '13.11'
type: development
group: group::package
default_enabled: false
# frozen_string_literal: true
class AddIndexToPackagesMavenMetadataPath < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
INDEX_NAME = 'index_packages_maven_metadata_on_path'
def up
add_concurrent_index :packages_maven_metadata, :path, name: INDEX_NAME
end
def down
remove_concurrent_index :packages_maven_metadata, :path, name: INDEX_NAME
end
end
2da634fa920e3989d9b8e53ddc1ba005e5bc0f4701426e3841d90a42bd2e908f
\ No newline at end of file
...@@ -23360,6 +23360,8 @@ CREATE INDEX index_packages_events_on_package_id ON packages_events USING btree ...@@ -23360,6 +23360,8 @@ CREATE INDEX index_packages_events_on_package_id ON packages_events USING btree
CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON packages_maven_metadata USING btree (package_id, path); CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON packages_maven_metadata USING btree (package_id, path);
CREATE INDEX index_packages_maven_metadata_on_path ON packages_maven_metadata USING btree (path);
CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id); CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_generic ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 7); CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_generic ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 7);
...@@ -23,6 +23,15 @@ module API ...@@ -23,6 +23,15 @@ module API
helpers ::API::Helpers::PackagesHelpers helpers ::API::Helpers::PackagesHelpers
helpers do helpers do
def path_exists?(path)
# return true when FF disabled so that processing the request is not stopped
return true unless Feature.enabled?(:check_maven_path_first)
return false if path.blank?
Packages::Maven::Metadatum.with_path(path)
.exists?
end
def extract_format(file_name) def extract_format(file_name)
name, _, format = file_name.rpartition('.') name, _, format = file_name.rpartition('.')
...@@ -104,6 +113,9 @@ module API ...@@ -104,6 +113,9 @@ module API
end end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get 'packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do get 'packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
# return a similar failure to authorize_read_package!(project)
forbidden! unless path_exists?(params[:path])
file_name, format = extract_format(params[:file_name]) file_name, format = extract_format(params[:file_name])
# To avoid name collision we require project path and project package be the same. # To avoid name collision we require project path and project package be the same.
...@@ -142,6 +154,9 @@ module API ...@@ -142,6 +154,9 @@ module API
end end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get ':id/-/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do get ':id/-/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
# return a similar failure to group = find_group(params[:id])
not_found!('Group') unless path_exists?(params[:path])
file_name, format = extract_format(params[:file_name]) file_name, format = extract_format(params[:file_name])
group = find_group(params[:id]) group = find_group(params[:id])
...@@ -181,6 +196,9 @@ module API ...@@ -181,6 +196,9 @@ module API
end end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do get ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
# return a similar failure to user_project
not_found!('Project') unless path_exists?(params[:path])
authorize_read_package!(user_project) authorize_read_package!(user_project)
file_name, format = extract_format(params[:file_name]) file_name, format = extract_format(params[:file_name])
......
...@@ -54,7 +54,7 @@ RSpec.describe Packages::Maven::Metadatum, type: :model do ...@@ -54,7 +54,7 @@ RSpec.describe Packages::Maven::Metadatum, type: :model do
let_it_be(:metadatum3) { create(:maven_metadatum, package: package) } let_it_be(:metadatum3) { create(:maven_metadatum, package: package) }
let_it_be(:metadatum4) { create(:maven_metadatum, package: package) } let_it_be(:metadatum4) { create(:maven_metadatum, package: package) }
subject { Packages::Maven::Metadatum.for_package_ids(package.id).order_created } subject { described_class.for_package_ids(package.id).order_created }
it { is_expected.to eq([metadatum1, metadatum2, metadatum3, metadatum4]) } it { is_expected.to eq([metadatum1, metadatum2, metadatum3, metadatum4]) }
end end
...@@ -64,10 +64,20 @@ RSpec.describe Packages::Maven::Metadatum, type: :model do ...@@ -64,10 +64,20 @@ RSpec.describe Packages::Maven::Metadatum, type: :model do
let_it_be(:metadatum2) { create(:maven_metadatum, package: package, app_name: 'two') } let_it_be(:metadatum2) { create(:maven_metadatum, package: package, app_name: 'two') }
let_it_be(:metadatum3) { create(:maven_metadatum, package: package, app_name: 'three') } let_it_be(:metadatum3) { create(:maven_metadatum, package: package, app_name: 'three') }
subject { Packages::Maven::Metadatum.for_package_ids(package.id).pluck_app_name } subject { described_class.for_package_ids(package.id).pluck_app_name }
it { is_expected.to match_array([metadatum1, metadatum2, metadatum3].map(&:app_name)) } it { is_expected.to match_array([metadatum1, metadatum2, metadatum3].map(&:app_name)) }
end end
describe '.with_path' do
let_it_be(:metadatum1) { create(:maven_metadatum, package: package, path: 'one') }
let_it_be(:metadatum2) { create(:maven_metadatum, package: package, path: 'two') }
let_it_be(:metadatum3) { create(:maven_metadatum, package: package, path: 'three') }
subject { described_class.with_path('two') }
it { is_expected.to match_array([metadatum2]) }
end
end end
end end
end end
...@@ -47,7 +47,21 @@ RSpec.describe API::MavenPackages do ...@@ -47,7 +47,21 @@ RSpec.describe API::MavenPackages do
end end
end end
shared_examples 'processing HEAD requests' do shared_examples 'rejecting the request for non existing maven path' do |expected_status: :not_found|
before do
if Feature.enabled?(:check_maven_path_first)
expect(::Packages::Maven::PackageFinder).not_to receive(:new)
end
end
it 'rejects the request' do
subject
expect(response).to have_gitlab_http_status(expected_status)
end
end
shared_examples 'processing HEAD requests' do |instance_level: false|
subject { head api(url) } subject { head api(url) }
before do before do
...@@ -92,6 +106,12 @@ RSpec.describe API::MavenPackages do ...@@ -92,6 +106,12 @@ RSpec.describe API::MavenPackages do
subject subject
end end
context 'with a non existing maven path' do
let(:path) { 'foo/bar/1.2.3' }
it_behaves_like 'rejecting the request for non existing maven path', expected_status: instance_level ? :forbidden : :not_found
end
end end
end end
...@@ -99,9 +119,8 @@ RSpec.describe API::MavenPackages do ...@@ -99,9 +119,8 @@ RSpec.describe API::MavenPackages do
context 'successful download' do context 'successful download' do
subject do subject do
download_file( download_file(
package_file.file_name, file_name: package_file.file_name,
{}, request_headers: { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token.token }
Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token.token
) )
end end
...@@ -126,7 +145,7 @@ RSpec.describe API::MavenPackages do ...@@ -126,7 +145,7 @@ RSpec.describe API::MavenPackages do
shared_examples 'downloads with a job token' do shared_examples 'downloads with a job token' do
context 'with a running job' do context 'with a running job' do
it 'allows download with job token' do it 'allows download with job token' do
download_file(package_file.file_name, job_token: job.token) download_file(file_name: package_file.file_name, params: { job_token: job.token })
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('application/octet-stream') expect(response.media_type).to eq('application/octet-stream')
...@@ -139,7 +158,7 @@ RSpec.describe API::MavenPackages do ...@@ -139,7 +158,7 @@ RSpec.describe API::MavenPackages do
end end
it 'returns unauthorized error' do it 'returns unauthorized error' do
download_file(package_file.file_name, job_token: job.token) download_file(file_name: package_file.file_name, params: { job_token: job.token })
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
end end
...@@ -149,7 +168,7 @@ RSpec.describe API::MavenPackages do ...@@ -149,7 +168,7 @@ RSpec.describe API::MavenPackages do
describe 'GET /api/v4/packages/maven/*path/:file_name' do describe 'GET /api/v4/packages/maven/*path/:file_name' do
shared_examples 'handling all conditions' do shared_examples 'handling all conditions' do
context 'a public project' do context 'a public project' do
subject { download_file(package_file.file_name) } subject { download_file(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -161,12 +180,18 @@ RSpec.describe API::MavenPackages do ...@@ -161,12 +180,18 @@ RSpec.describe API::MavenPackages do
end end
it 'returns sha1 of the file' do it 'returns sha1 of the file' do
download_file(package_file.file_name + '.sha1') download_file(file_name: package_file.file_name + '.sha1')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('text/plain') expect(response.media_type).to eq('text/plain')
expect(response.body).to eq(package_file.file_sha1) expect(response.body).to eq(package_file.file_sha1)
end end
context 'with a non existing maven path' do
subject { download_file(file_name: package_file.file_name, path: 'foo/bar/1.2.3') }
it_behaves_like 'rejecting the request for non existing maven path', expected_status: :forbidden
end
end end
context 'internal project' do context 'internal project' do
...@@ -175,7 +200,7 @@ RSpec.describe API::MavenPackages do ...@@ -175,7 +200,7 @@ RSpec.describe API::MavenPackages do
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end end
subject { download_file_with_token(package_file.file_name) } subject { download_file_with_token(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -187,7 +212,7 @@ RSpec.describe API::MavenPackages do ...@@ -187,7 +212,7 @@ RSpec.describe API::MavenPackages do
end end
it 'denies download when no private token' do it 'denies download when no private token' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end end
...@@ -195,10 +220,16 @@ RSpec.describe API::MavenPackages do ...@@ -195,10 +220,16 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'downloads with a job token' it_behaves_like 'downloads with a job token'
it_behaves_like 'downloads with a deploy token' it_behaves_like 'downloads with a deploy token'
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') }
it_behaves_like 'rejecting the request for non existing maven path', expected_status: :forbidden
end
end end
context 'private project' do context 'private project' do
subject { download_file_with_token(package_file.file_name) } subject { download_file_with_token(file_name: package_file.file_name) }
before do before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
...@@ -222,7 +253,7 @@ RSpec.describe API::MavenPackages do ...@@ -222,7 +253,7 @@ RSpec.describe API::MavenPackages do
end end
it 'denies download when no private token' do it 'denies download when no private token' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end end
...@@ -241,13 +272,18 @@ RSpec.describe API::MavenPackages do ...@@ -241,13 +272,18 @@ RSpec.describe API::MavenPackages do
unauthorized_deploy_token.update!(id: another_user.id) unauthorized_deploy_token.update!(id: another_user.id)
download_file( download_file(
package_file.file_name, file_name: package_file.file_name,
{}, request_headers: { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => unauthorized_deploy_token.token }
Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => unauthorized_deploy_token.token
) )
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end 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') }
it_behaves_like 'rejecting the request for non existing maven path', expected_status: :forbidden
end
end end
context 'project name is different from a package name' do context 'project name is different from a package name' do
...@@ -256,7 +292,7 @@ RSpec.describe API::MavenPackages do ...@@ -256,7 +292,7 @@ RSpec.describe API::MavenPackages do
end end
it 'rejects request' do it 'rejects request' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end end
...@@ -279,26 +315,43 @@ RSpec.describe API::MavenPackages do ...@@ -279,26 +315,43 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'handling all conditions' it_behaves_like 'handling all conditions'
end end
def download_file(file_name, params = {}, request_headers = headers) context 'with check_maven_path_first enabled' do
get api("/packages/maven/#{maven_metadatum.path}/#{file_name}"), params: params, headers: request_headers before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'handling all conditions'
end end
def download_file_with_token(file_name, params = {}, request_headers = headers_with_token) context 'with check_maven_path_first disabled' do
download_file(file_name, params, request_headers) before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'handling all conditions'
end
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
end
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)
end end
end end
describe 'HEAD /api/v4/packages/maven/*path/:file_name' do describe 'HEAD /api/v4/packages/maven/*path/:file_name' do
let(:url) { "/packages/maven/#{package.maven_metadatum.path}/#{package_file.file_name}" } let(:path) { package.maven_metadatum.path }
let(:url) { "/packages/maven/#{path}/#{package_file.file_name}" }
it_behaves_like 'processing HEAD requests' it_behaves_like 'processing HEAD requests', instance_level: true
context 'with maven_packages_group_level_improvements enabled' do context 'with maven_packages_group_level_improvements enabled' do
before do before do
stub_feature_flags(maven_packages_group_level_improvements: true) stub_feature_flags(maven_packages_group_level_improvements: true)
end end
it_behaves_like 'processing HEAD requests' it_behaves_like 'processing HEAD requests', instance_level: true
end end
context 'with maven_packages_group_level_improvements disabled' do context 'with maven_packages_group_level_improvements disabled' do
...@@ -306,7 +359,23 @@ RSpec.describe API::MavenPackages do ...@@ -306,7 +359,23 @@ RSpec.describe API::MavenPackages do
stub_feature_flags(maven_packages_group_level_improvements: false) stub_feature_flags(maven_packages_group_level_improvements: false)
end end
it_behaves_like 'processing HEAD requests' it_behaves_like 'processing HEAD requests', instance_level: true
end
context 'with check_maven_path_first enabled' do
before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'processing HEAD requests', instance_level: true
end
context 'with check_maven_path_first disabled' do
before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'processing HEAD requests', instance_level: true
end end
end end
...@@ -318,7 +387,7 @@ RSpec.describe API::MavenPackages do ...@@ -318,7 +387,7 @@ RSpec.describe API::MavenPackages do
shared_examples 'handling all conditions' do shared_examples 'handling all conditions' do
context 'a public project' do context 'a public project' do
subject { download_file(package_file.file_name) } subject { download_file(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -330,12 +399,18 @@ RSpec.describe API::MavenPackages do ...@@ -330,12 +399,18 @@ RSpec.describe API::MavenPackages do
end end
it 'returns sha1 of the file' do it 'returns sha1 of the file' do
download_file(package_file.file_name + '.sha1') download_file(file_name: package_file.file_name + '.sha1')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('text/plain') expect(response.media_type).to eq('text/plain')
expect(response.body).to eq(package_file.file_sha1) expect(response.body).to eq(package_file.file_sha1)
end end
context 'with a non existing maven path' do
subject { download_file(file_name: package_file.file_name, path: 'foo/bar/1.2.3') }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
context 'internal project' do context 'internal project' do
...@@ -344,7 +419,7 @@ RSpec.describe API::MavenPackages do ...@@ -344,7 +419,7 @@ RSpec.describe API::MavenPackages do
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end end
subject { download_file_with_token(package_file.file_name) } subject { download_file_with_token(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -356,7 +431,7 @@ RSpec.describe API::MavenPackages do ...@@ -356,7 +431,7 @@ RSpec.describe API::MavenPackages do
end end
it 'denies download when no private token' do it 'denies download when no private token' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
...@@ -364,6 +439,12 @@ RSpec.describe API::MavenPackages do ...@@ -364,6 +439,12 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'downloads with a job token' it_behaves_like 'downloads with a job token'
it_behaves_like 'downloads with a deploy token' it_behaves_like 'downloads with a deploy token'
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') }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
context 'private project' do context 'private project' do
...@@ -371,7 +452,7 @@ RSpec.describe API::MavenPackages do ...@@ -371,7 +452,7 @@ RSpec.describe API::MavenPackages do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end end
subject { download_file_with_token(package_file.file_name) } subject { download_file_with_token(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -392,7 +473,7 @@ RSpec.describe API::MavenPackages do ...@@ -392,7 +473,7 @@ RSpec.describe API::MavenPackages do
end end
it 'denies download when no private token' do it 'denies download when no private token' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
...@@ -401,8 +482,14 @@ RSpec.describe API::MavenPackages do ...@@ -401,8 +482,14 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'downloads with a deploy token' it_behaves_like 'downloads with a deploy token'
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') }
it_behaves_like 'rejecting the request for non existing maven path'
end
context 'with group deploy token' do context 'with group deploy token' do
subject { download_file_with_token(package_file.file_name, {}, group_deploy_token_headers) } subject { download_file_with_token(file_name: package_file.file_name, request_headers: group_deploy_token_headers) }
it 'returns the file' do it 'returns the file' do
subject subject
...@@ -419,13 +506,19 @@ RSpec.describe API::MavenPackages do ...@@ -419,13 +506,19 @@ RSpec.describe API::MavenPackages do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('application/octet-stream') expect(response.media_type).to eq('application/octet-stream')
end 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) }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
context 'with a reporter from a subgroup accessing the root group' do context 'with a reporter from a subgroup accessing the root group' do
let_it_be(:root_group) { create(:group, :private) } let_it_be(:root_group) { create(:group, :private) }
let_it_be(:group) { create(:group, :private, parent: root_group) } let_it_be(:group) { create(:group, :private, parent: root_group) }
subject { download_file_with_token(package_file.file_name, {}, headers_with_token, root_group.id) } subject { download_file_with_token(file_name: package_file.file_name, request_headers: headers_with_token, group_id: root_group.id) }
before do before do
project.update!(namespace: group) project.update!(namespace: group)
...@@ -438,6 +531,12 @@ RSpec.describe API::MavenPackages do ...@@ -438,6 +531,12 @@ RSpec.describe API::MavenPackages do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('application/octet-stream') expect(response.media_type).to eq('application/octet-stream')
end 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: headers_with_token, group_id: root_group.id) }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
end end
...@@ -457,7 +556,7 @@ RSpec.describe API::MavenPackages do ...@@ -457,7 +556,7 @@ RSpec.describe API::MavenPackages do
let(:maven_metadatum) { package3.maven_metadatum } let(:maven_metadatum) { package3.maven_metadatum }
subject { download_file_with_token(package_file3.file_name) } subject { download_file_with_token(file_name: package_file3.file_name) }
before do before do
sub_group1.add_developer(user) sub_group1.add_developer(user)
...@@ -511,17 +610,34 @@ RSpec.describe API::MavenPackages do ...@@ -511,17 +610,34 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'handling all conditions' it_behaves_like 'handling all conditions'
end end
def download_file(file_name, params = {}, request_headers = headers, group_id = group.id) context 'with check_maven_path_first enabled' do
get api("/groups/#{group_id}/-/packages/maven/#{maven_metadatum.path}/#{file_name}"), params: params, headers: request_headers before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'handling all conditions'
end
context 'with check_maven_path_first disabled' do
before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'handling all conditions'
end
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 end
def download_file_with_token(file_name, params = {}, request_headers = headers_with_token, group_id = group.id) 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, params, request_headers, group_id) download_file(file_name: file_name, params: params, request_headers: request_headers, path: path, group_id: group_id)
end end
end end
describe 'HEAD /api/v4/groups/:id/-/packages/maven/*path/:file_name' do describe 'HEAD /api/v4/groups/:id/-/packages/maven/*path/:file_name' do
let(:url) { "/groups/#{group.id}/-/packages/maven/#{package.maven_metadatum.path}/#{package_file.file_name}" } let(:path) { package.maven_metadatum.path }
let(:url) { "/groups/#{group.id}/-/packages/maven/#{path}/#{package_file.file_name}" }
context 'with maven_packages_group_level_improvements enabled' do context 'with maven_packages_group_level_improvements enabled' do
before do before do
...@@ -538,12 +654,28 @@ RSpec.describe API::MavenPackages do ...@@ -538,12 +654,28 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'processing HEAD requests' it_behaves_like 'processing HEAD requests'
end end
context 'with check_maven_path_first enabled' do
before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'processing HEAD requests'
end
context 'with check_maven_path_first disabled' do
before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'processing HEAD requests'
end
end end
describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do
shared_examples 'handling all conditions' do shared_examples 'handling all conditions' do
context 'a public project' do context 'a public project' do
subject { download_file(package_file.file_name) } subject { download_file(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -555,12 +687,18 @@ RSpec.describe API::MavenPackages do ...@@ -555,12 +687,18 @@ RSpec.describe API::MavenPackages do
end end
it 'returns sha1 of the file' do it 'returns sha1 of the file' do
download_file(package_file.file_name + '.sha1') download_file(file_name: package_file.file_name + '.sha1')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq('text/plain') expect(response.media_type).to eq('text/plain')
expect(response.body).to eq(package_file.file_sha1) expect(response.body).to eq(package_file.file_sha1)
end end
context 'with a non existing maven path' do
subject { download_file(file_name: package_file.file_name, path: 'foo/bar/1.2.3') }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
context 'private project' do context 'private project' do
...@@ -568,7 +706,7 @@ RSpec.describe API::MavenPackages do ...@@ -568,7 +706,7 @@ RSpec.describe API::MavenPackages do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end end
subject { download_file_with_token(package_file.file_name) } subject { download_file_with_token(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event' it_behaves_like 'tracking the file download event'
...@@ -588,7 +726,7 @@ RSpec.describe API::MavenPackages do ...@@ -588,7 +726,7 @@ RSpec.describe API::MavenPackages do
end end
it 'denies download when no private token' do it 'denies download when no private token' do
download_file(package_file.file_name) download_file(file_name: package_file.file_name)
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
...@@ -596,6 +734,12 @@ RSpec.describe API::MavenPackages do ...@@ -596,6 +734,12 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'downloads with a job token' it_behaves_like 'downloads with a job token'
it_behaves_like 'downloads with a deploy token' it_behaves_like 'downloads with a deploy token'
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') }
it_behaves_like 'rejecting the request for non existing maven path'
end
end end
end end
...@@ -615,18 +759,35 @@ RSpec.describe API::MavenPackages do ...@@ -615,18 +759,35 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'handling all conditions' it_behaves_like 'handling all conditions'
end end
def download_file(file_name, params = {}, request_headers = headers) context 'with check_maven_path_first enabled' do
before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'handling all conditions'
end
context 'with check_maven_path_first disabled' do
before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'handling all conditions'
end
def download_file(file_name:, params: {}, request_headers: headers, path: maven_metadatum.path)
get api("/projects/#{project.id}/packages/maven/" \ get api("/projects/#{project.id}/packages/maven/" \
"#{maven_metadatum.path}/#{file_name}"), params: params, headers: request_headers "#{path}/#{file_name}"), params: params, headers: request_headers
end end
def download_file_with_token(file_name, params = {}, request_headers = headers_with_token) def download_file_with_token(file_name:, params: {}, request_headers: headers_with_token, path: maven_metadatum.path)
download_file(file_name, params, request_headers) download_file(file_name: file_name, params: params, request_headers: request_headers, path: path)
end end
end end
describe 'HEAD /api/v4/projects/:id/packages/maven/*path/:file_name' do describe 'HEAD /api/v4/projects/:id/packages/maven/*path/:file_name' do
let(:url) { "/projects/#{project.id}/packages/maven/#{package.maven_metadatum.path}/#{package_file.file_name}" } let(:path) { package.maven_metadatum.path }
let(:url) { "/projects/#{project.id}/packages/maven/#{path}/#{package_file.file_name}" }
context 'with maven_packages_group_level_improvements enabled' do context 'with maven_packages_group_level_improvements enabled' do
before do before do
...@@ -643,11 +804,27 @@ RSpec.describe API::MavenPackages do ...@@ -643,11 +804,27 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'processing HEAD requests' it_behaves_like 'processing HEAD requests'
end end
context 'with check_maven_path_first enabled' do
before do
stub_feature_flags(check_maven_path_first: true)
end
it_behaves_like 'processing HEAD requests'
end
context 'with check_maven_path_first disabled' do
before do
stub_feature_flags(check_maven_path_first: false)
end
it_behaves_like 'processing HEAD requests'
end
end end
describe 'PUT /api/v4/projects/:id/packages/maven/*path/:file_name/authorize' do describe 'PUT /api/v4/projects/:id/packages/maven/*path/:file_name/authorize' do
it 'rejects a malicious request' do it 'rejects a malicious request' do
put api("/projects/#{project.id}/packages/maven/com/example/my-app/#{version}/%2e%2e%2F.ssh%2Fauthorized_keys/authorize"), params: {}, headers: headers_with_token put api("/projects/#{project.id}/packages/maven/com/example/my-app/#{version}/%2e%2e%2F.ssh%2Fauthorized_keys/authorize"), headers: headers_with_token
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
end end
......
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