Commit 07fd8655 authored by Giorgenes Gelatti's avatar Giorgenes Gelatti

Handle composer branch/tag retrieval

Validates and retrieve branch or tag for
PHP Composer package publish
parent 3442487e
......@@ -74,11 +74,11 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
unless ::Feature.enabled?(:composer_packages, authorized_user_project)
unless ::Feature.enabled?(:composer_packages, unauthorized_user_project!)
not_found!
end
authorize_packages_feature!(authorized_user_project)
authorize_packages_feature!(unauthorized_user_project!)
end
desc 'Composer packages endpoint for registering packages'
......@@ -92,6 +92,14 @@ module API
post do
authorize_create_package!(authorized_user_project)
if params[:branch].present?
find_branch!(params[:branch])
elsif params[:tag].present?
find_tag!(params[:tag])
else
bad_request!
end
created!
end
end
......
......@@ -7,7 +7,7 @@ describe API::ComposerPackages do
let_it_be(:user) { create(:user) }
let_it_be(:group, reload: true) { create(:group, :public) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:project, reload: true) { create(:project, :public) }
let_it_be(:project, reload: true) { create(:project, :repository, path: 'my.project') }
describe 'GET /api/v4/group/:id/-/packages/composer/packages' do
let(:url) { "/group/#{group.id}/-/packages/composer/packages.json" }
......@@ -175,54 +175,104 @@ describe API::ComposerPackages do
describe 'POST /api/v4/projects/:id/packages/composer' do
let(:url) { "/projects/#{project.id}/packages/composer" }
let(:params) { { branch: 'foobar' } }
let(:params) { {} }
subject { post api(url), headers: headers }
subject { post api(url), headers: headers, params: params }
shared_examples 'composer package publish' do
context 'with packages features enabled' do
before do
stub_licensed_features(packages: true)
end
context 'with valid project' do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
'PUBLIC' | :developer | true | true | 'process Composer api request' | :created
'PUBLIC' | :guest | true | true | 'process Composer api request' | :forbidden
'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :developer | false | true | 'process Composer api request' | :forbidden
'PUBLIC' | :guest | false | true | 'process Composer api request' | :forbidden
'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :anonymous | false | true | 'process Composer api request' | :unauthorized
'PRIVATE' | :developer | true | true | 'process Composer api request' | :created
'PRIVATE' | :guest | true | true | 'process Composer api request' | :forbidden
'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :unauthorized
end
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : build_basic_auth_header(user.username, token) }
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
end
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
end
end
it_behaves_like 'rejects Composer access with unknown project id'
end
end
it_behaves_like 'rejects Composer packages access with packages features disabled'
context 'with no tag or branch params' do
let(:headers) { build_basic_auth_header(user.username, personal_access_token.token) }
context 'with packages features enabled' do
before do
stub_licensed_features(packages: true)
end
context 'with valid project' do
using RSpec::Parameterized::TableSyntax
it_behaves_like 'process Composer api request', :developer, :bad_request
end
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
'PUBLIC' | :developer | true | true | 'process Composer api request' | :created
'PUBLIC' | :guest | true | true | 'process Composer api request' | :forbidden
'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :developer | false | true | 'process Composer api request' | :forbidden
'PUBLIC' | :guest | false | true | 'process Composer api request' | :forbidden
'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized
'PUBLIC' | :anonymous | false | true | 'process Composer api request' | :unauthorized
'PRIVATE' | :developer | true | true | 'process Composer api request' | :created
'PRIVATE' | :guest | true | true | 'process Composer api request' | :forbidden
'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found
'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found
'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized
'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :unauthorized
end
context 'with a tag' do
context 'with an existing branch' do
let(:params) { { tag: 'v1.0.0' } }
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : build_basic_auth_header(user.username, token) }
it_behaves_like 'composer package publish'
end
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
end
context 'with a non existing tag' do
let(:params) { { tag: 'non-existing-tag' } }
let(:headers) { build_basic_auth_header(user.username, personal_access_token.token) }
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
before do
stub_licensed_features(packages: true)
end
end
it_behaves_like 'rejects Composer access with unknown project id'
it_behaves_like 'process Composer api request', :developer, :not_found
end
end
it_behaves_like 'rejects Composer packages access with packages features disabled'
context 'with a branch' do
context 'with an existing branch' do
let(:params) { { branch: 'feature' } }
it_behaves_like 'composer package publish'
end
context 'with a non existing branch' do
let(:params) { { branch: 'non-existing-branch' } }
let(:headers) { build_basic_auth_header(user.username, personal_access_token.token) }
before do
stub_licensed_features(packages: true)
end
it_behaves_like 'process Composer api request', :developer, :not_found
end
end
end
end
......@@ -42,7 +42,7 @@ RSpec.shared_examples 'rejects Composer access with unknown project id' do
let(:project) { double(id: non_existing_record_id) }
context 'as anonymous' do
it_behaves_like 'process PyPi api request', :anonymous, :unauthorized
it_behaves_like 'process PyPi api request', :anonymous, :not_found
end
context 'as authenticated user' do
......
......@@ -179,6 +179,14 @@ module API
end
end
def find_tag!(tag_name)
if Gitlab::GitRefValidator.validate(tag_name)
user_project.repository.find_tag(tag_name) || not_found!('Tag')
else
render_api_error!('The tag refname is invalid', 400)
end
end
# rubocop: disable CodeReuse/ActiveRecord
def find_project_issue(iid, project_id = nil)
project = project_id ? find_project!(project_id) : user_project
......
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