Commit f23e5876 authored by David Fernandez's avatar David Fernandez

Lift the NPM naming convention constraint

For the project level Package Manager API.

At the instance level, the API will only return packages that follow
the naming convention.

Documentation: https://docs.gitlab.com/ee/user/packages/npm_registry/#package-naming-convention
parent 77ea020f
...@@ -2,29 +2,41 @@ ...@@ -2,29 +2,41 @@
module Packages module Packages
module Npm module Npm
class PackageFinder class PackageFinder
attr_reader :project, :package_name
delegate :find_by_version, to: :execute delegate :find_by_version, to: :execute
delegate :last, to: :execute
def initialize(project, package_name) def initialize(package_name, project: nil, namespace: nil)
@project = project
@package_name = package_name @package_name = package_name
@project = project
@namespace = namespace
end end
def execute def execute
return Packages::Package.none unless project base.npm
.with_name(@package_name)
packages .last_of_each_version
.preload_files
end end
private private
def packages def base
project.packages if @project
.npm packages_for_project
.with_name(package_name) elsif @namespace
.last_of_each_version packages_for_namespace
.preload_files else
::Packages::Package.none
end
end
def packages_for_project
@project.packages
end
def packages_for_namespace
projects = ::Project.in_namespace(@namespace.self_and_descendants.select(:id))
::Packages::Package.for_projects(projects.select(:id))
end end
end end
end end
......
...@@ -40,11 +40,11 @@ class Packages::Package < ApplicationRecord ...@@ -40,11 +40,11 @@ class Packages::Package < ApplicationRecord
validate :unique_debian_package_name, if: :debian_package? validate :unique_debian_package_name, if: :debian_package?
validate :valid_conan_package_recipe, if: :conan? validate :valid_conan_package_recipe, if: :conan?
validate :valid_npm_package_name, if: :npm?
validate :valid_composer_global_name, if: :composer? validate :valid_composer_global_name, if: :composer?
validate :package_already_taken, if: :npm? validate :package_already_taken, if: :npm?
validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan? validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic? validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic?
validates :name, format: { with: Gitlab::Regex.npm_package_name_regex }, if: :npm?
validates :name, format: { with: Gitlab::Regex.nuget_package_name_regex }, if: :nuget? validates :name, format: { with: Gitlab::Regex.nuget_package_name_regex }, if: :nuget?
validates :name, format: { with: Gitlab::Regex.debian_package_name_regex }, if: :debian_package? validates :name, format: { with: Gitlab::Regex.debian_package_name_regex }, if: :debian_package?
validates :name, inclusion: { in: %w[incoming] }, if: :debian_incoming? validates :name, inclusion: { in: %w[incoming] }, if: :debian_incoming?
...@@ -247,14 +247,6 @@ class Packages::Package < ApplicationRecord ...@@ -247,14 +247,6 @@ class Packages::Package < ApplicationRecord
end end
end end
def valid_npm_package_name
return unless project&.root_namespace
unless name =~ %r{\A@#{project.root_namespace.path}/[^/]+\z}
errors.add(:name, 'is not valid')
end
end
def package_already_taken def package_already_taken
return unless project return unless project
......
---
title: Lift the NPM package naming convention for the project level API
merge_request: 53266
author:
type: changed
...@@ -86,7 +86,9 @@ A `package.json` file is created. ...@@ -86,7 +86,9 @@ A `package.json` file is created.
To use the GitLab endpoint for npm packages, choose an option: To use the GitLab endpoint for npm packages, choose an option:
- **Project-level**: Use when you have few npm packages and they are not in - **Project-level**: Use when you have few npm packages and they are not in
the same GitLab group. the same GitLab group. The [package naming convention](#package-naming-convention) is not enforced at this level.
Instead, you should use a [scope](https://docs.npmjs.com/cli/v6/using-npm/scope) for your package.
When you use a scope, the registry URL is [updated](#authenticate-to-the-package-registry) only for that scope.
- **Instance-level**: Use when you have many npm packages in different - **Instance-level**: Use when you have many npm packages in different
GitLab groups or in their own namespace. Be sure to comply with the [package naming convention](#package-naming-convention). GitLab groups or in their own namespace. Be sure to comply with the [package naming convention](#package-naming-convention).
...@@ -204,7 +206,7 @@ Then, you can run `npm publish` either locally or by using GitLab CI/CD. ...@@ -204,7 +206,7 @@ Then, you can run `npm publish` either locally or by using GitLab CI/CD.
## Package naming convention ## Package naming convention
Your npm package name must be in the format of `@scope/package-name`. When you use the [instance-level endpoint](#use-the-gitlab-endpoint-for-npm-packages), only the packages with names in the format of `@scope/package-name` are available.
- The `@scope` is the root namespace of the GitLab project. It must match exactly, including the case. - The `@scope` is the root namespace of the GitLab project. It must match exactly, including the case.
- The `package-name` can be whatever you want. - The `package-name` can be whatever you want.
...@@ -302,8 +304,9 @@ the same version more than once, even if it has been deleted. ...@@ -302,8 +304,9 @@ the same version more than once, even if it has been deleted.
## Install a package ## Install a package
npm packages are commonly-installed by using the `npm` or `yarn` commands npm packages are commonly-installed by using the `npm` or `yarn` commands
in a JavaScript project. You can install a package from the scope of a project, group, in a JavaScript project. You can install a package from the scope of a project or instance.
or instance.
If multiple packages have the same name and version, when you install a package, the most recently-published package is retrieved.
1. Set the URL for scoped packages by running: 1. Set the URL for scoped packages by running:
......
...@@ -41,8 +41,8 @@ module API ...@@ -41,8 +41,8 @@ module API
authorize_read_package!(project) authorize_read_package!(project)
packages = ::Packages::Npm::PackageFinder.new(project, package_name) packages = ::Packages::Npm::PackageFinder.new(package_name, project: project)
.execute .execute
not_found! if packages.empty? not_found! if packages.empty?
...@@ -68,9 +68,8 @@ module API ...@@ -68,9 +68,8 @@ module API
authorize_create_package!(project) authorize_create_package!(project)
package = ::Packages::Npm::PackageFinder package = ::Packages::Npm::PackageFinder.new(package_name, project: project)
.new(project, package_name) .find_by_version(version)
.find_by_version(version)
not_found!('Package') unless package not_found!('Package') unless package
::Packages::Npm::CreateTagService.new(package, tag).execute ::Packages::Npm::CreateTagService.new(package, tag).execute
...@@ -112,9 +111,8 @@ module API ...@@ -112,9 +111,8 @@ module API
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
package_name = params[:package_name] package_name = params[:package_name]
packages = ::Packages::Npm::PackageFinder.new(package_name, project: project_or_nil)
packages = ::Packages::Npm::PackageFinder.new(project_or_nil, package_name) .execute
.execute
redirect_request = project_or_nil.blank? || packages.empty? redirect_request = project_or_nil.blank? || packages.empty?
......
...@@ -49,13 +49,34 @@ module API ...@@ -49,13 +49,34 @@ module API
when :project when :project
params[:id] params[:id]
when :instance when :instance
::Packages::Package.npm namespace_path = namespace_path_from_package_name
.with_name(params[:package_name]) next unless namespace_path
.first
&.project_id namespace = namespace_from_path(namespace_path)
next unless namespace
finder = ::Packages::Npm::PackageFinder.new(params[:package_name], namespace: namespace)
finder.last&.project_id
end end
end end
end end
# from "@scope/package-name" return "scope" or nil
def namespace_path_from_package_name
package_name = params[:package_name]
return unless package_name.starts_with?('@')
return unless package_name.include?('/')
package_name.match(Gitlab::Regex.npm_package_name_regex)&.captures&.first
end
def namespace_from_path(path)
group = Group.by_path(path)
return group if group
Namespace.for_user.by_path(path)
end
end end
end end
end end
......
...@@ -61,6 +61,10 @@ module Gitlab ...@@ -61,6 +61,10 @@ module Gitlab
maven_app_name_regex maven_app_name_regex
end end
def npm_package_name_regex
@npm_package_name_regex ||= %r{\A(?:@(#{Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX})/)?[-+\.\_a-zA-Z0-9]+\z}
end
def nuget_package_name_regex def nuget_package_name_regex
@nuget_package_name_regex ||= %r{\A[-+\.\_a-zA-Z0-9]+\z}.freeze @nuget_package_name_regex ||= %r{\A[-+\.\_a-zA-Z0-9]+\z}.freeze
end end
......
...@@ -2,39 +2,139 @@ ...@@ -2,39 +2,139 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe ::Packages::Npm::PackageFinder do RSpec.describe ::Packages::Npm::PackageFinder do
let(:package) { create(:npm_package) } let_it_be_with_reload(:project) { create(:project)}
let_it_be(:package) { create(:npm_package, project: project) }
let(:project) { package.project } let(:project) { package.project }
let(:package_name) { package.name } let(:package_name) { package.name }
describe '#execute!' do shared_examples 'accepting a namespace for' do |example_name|
subject { described_class.new(project, package_name).execute } before do
project.update!(namespace: namespace)
end
context 'that is a group' do
let_it_be(:namespace) { create(:group) }
it_behaves_like example_name
context 'within another group' do
let_it_be(:subgroup) { create(:group, parent: namespace) }
before do
project.update!(namespace: subgroup)
end
it_behaves_like example_name
end
end
context 'that is a user namespace' do
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { user.namespace }
it_behaves_like example_name
end
end
describe '#execute' do
shared_examples 'finding packages by name' do
it { is_expected.to eq([package]) }
context 'with unknown package name' do
let(:package_name) { 'baz' }
it { is_expected.to be_empty }
end
end
subject { finder.execute }
context 'with a project' do
let(:finder) { described_class.new(package_name, project: project) }
it { is_expected.to eq([package]) } it_behaves_like 'finding packages by name'
context 'with unknown package name' do context 'set to nil' do
let(:package_name) { 'baz' } let(:project) { nil }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end
end end
context 'with nil project' do context 'with a namespace' do
let(:project) { nil } let(:finder) { described_class.new(package_name, namespace: namespace) }
it_behaves_like 'accepting a namespace for', 'finding packages by name'
context 'set to nil' do
let_it_be(:namespace) { nil }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end
end end
end end
describe '#find_by_version' do describe '#find_by_version' do
let(:version) { package.version } let(:version) { package.version }
subject { described_class.new(project, package.name).find_by_version(version) } subject { finder.find_by_version(version) }
shared_examples 'finding packages by version' do
it { is_expected.to eq(package) }
context 'with unknown version' do
let(:version) { 'foobar' }
it { is_expected.to be_nil }
end
end
context 'with a project' do
let(:finder) { described_class.new(package_name, project: project) }
it_behaves_like 'finding packages by version'
end
context 'with a namespace' do
let(:finder) { described_class.new(package_name, namespace: namespace) }
it_behaves_like 'accepting a namespace for', 'finding packages by version'
end
end
describe '#last' do
subject { finder.last }
shared_examples 'finding package by last' do
it { is_expected.to eq(package) }
end
context 'with a project' do
let(:finder) { described_class.new(package_name, project: project) }
it_behaves_like 'finding package by last'
end
context 'with a namespace' do
let(:finder) { described_class.new(package_name, namespace: namespace) }
it_behaves_like 'accepting a namespace for', 'finding package by last'
it { is_expected.to eq(package) } context 'with duplicate packages' do
let_it_be(:namespace) { create(:group) }
let_it_be(:subgroup1) { create(:group, parent: namespace) }
let_it_be(:subgroup2) { create(:group, parent: namespace) }
let_it_be(:project2) { create(:project, namespace: subgroup2) }
let_it_be(:package2) { create(:npm_package, name: package.name, project: project2) }
context 'with unknown version' do before do
let(:version) { 'foobar' } project.update!(namespace: subgroup1)
end
it { is_expected.to be_nil } # the most recent one is returned
it { is_expected.to eq(package2) }
end
end end
end end
end end
...@@ -367,6 +367,35 @@ RSpec.describe Gitlab::Regex do ...@@ -367,6 +367,35 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('%2e%2e%2f1.2.3') } it { is_expected.not_to match('%2e%2e%2f1.2.3') }
end end
describe '.npm_package_name_regex' do
subject { described_class.npm_package_name_regex }
it { is_expected.to match('@scope/package') }
it { is_expected.to match('unscoped-package') }
it { is_expected.not_to match('@first-scope@second-scope/package') }
it { is_expected.not_to match('scope-without-at-symbol/package') }
it { is_expected.not_to match('@not-a-scoped-package') }
it { is_expected.not_to match('@scope/sub/package') }
it { is_expected.not_to match('@scope/../../package') }
it { is_expected.not_to match('@scope%2e%2e%2fpackage') }
it { is_expected.not_to match('@%2e%2e%2f/package') }
context 'capturing group' do
[
['@scope/package', 'scope'],
['unscoped-package', nil],
['@not-a-scoped-package', nil],
['@scope/sub/package', nil],
['@inv@lid-scope/package', nil]
].each do |package_name, extracted_scope_name|
it "extracts the scope name for #{package_name}" do
match = package_name.match(described_class.npm_package_name_regex)
expect(match&.captures&.first).to eq(extracted_scope_name)
end
end
end
end
describe '.nuget_version_regex' do describe '.nuget_version_regex' do
subject { described_class.nuget_version_regex } subject { described_class.nuget_version_regex }
......
...@@ -162,6 +162,18 @@ RSpec.describe Packages::Package, type: :model do ...@@ -162,6 +162,18 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.not_to allow_value('../../../my_package').for(:name) } it { is_expected.not_to allow_value('../../../my_package').for(:name) }
it { is_expected.not_to allow_value('%2e%2e%2fmy_package').for(:name) } it { is_expected.not_to allow_value('%2e%2e%2fmy_package').for(:name) }
end end
context 'npm package' do
subject { build_stubbed(:npm_package) }
it { is_expected.to allow_value("@group-1/package").for(:name) }
it { is_expected.to allow_value("@any-scope/package").for(:name) }
it { is_expected.to allow_value("unscoped-package").for(:name) }
it { is_expected.not_to allow_value("@inv@lid-scope/package").for(:name) }
it { is_expected.not_to allow_value("@scope/../../package").for(:name) }
it { is_expected.not_to allow_value("@scope%2e%2e%fpackage").for(:name) }
it { is_expected.not_to allow_value("@scope/sub/package").for(:name) }
end
end end
describe '#version' do describe '#version' do
...@@ -342,16 +354,6 @@ RSpec.describe Packages::Package, type: :model do ...@@ -342,16 +354,6 @@ RSpec.describe Packages::Package, type: :model do
end end
describe '#package_already_taken' do describe '#package_already_taken' do
context 'npm package' do
let!(:package) { create(:npm_package) }
it 'will not allow a package of the same name' do
new_package = build(:npm_package, project: create(:project), name: package.name)
expect(new_package).not_to be_valid
end
end
context 'maven package' do context 'maven package' do
let!(:package) { create(:maven_package) } let!(:package) { create(:maven_package) }
......
...@@ -30,7 +30,7 @@ RSpec.describe API::NpmProjectPackages do ...@@ -30,7 +30,7 @@ RSpec.describe API::NpmProjectPackages do
end end
describe 'GET /api/v4/projects/:id/packages/npm/*package_name/-/*file_name' do describe 'GET /api/v4/projects/:id/packages/npm/*package_name/-/*file_name' do
let_it_be(:package_file) { package.package_files.first } let(:package_file) { package.package_files.first }
let(:headers) { {} } let(:headers) { {} }
let(:url) { api("/projects/#{project.id}/packages/npm/#{package.name}/-/#{package_file.file_name}") } let(:url) { api("/projects/#{project.id}/packages/npm/#{package.name}/-/#{package_file.file_name}") }
...@@ -127,24 +127,6 @@ RSpec.describe API::NpmProjectPackages do ...@@ -127,24 +127,6 @@ RSpec.describe API::NpmProjectPackages do
context 'when params are correct' do context 'when params are correct' do
context 'invalid package record' do context 'invalid package record' do
context 'unscoped package' do
let(:package_name) { 'my_unscoped_package' }
let(:params) { upload_params(package_name: package_name) }
it_behaves_like 'handling invalid record with 400 error'
context 'with empty versions' do
let(:params) { upload_params(package_name: package_name).merge!(versions: {}) }
it 'throws a 400 error' do
expect { upload_package_with_token(package_name, params) }
.not_to change { project.packages.count }
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
context 'invalid package name' do context 'invalid package name' do
let(:package_name) { "@#{group.path}/my_inv@@lid_package_name" } let(:package_name) { "@#{group.path}/my_inv@@lid_package_name" }
let(:params) { upload_params(package_name: package_name) } let(:params) { upload_params(package_name: package_name) }
...@@ -175,52 +157,71 @@ RSpec.describe API::NpmProjectPackages do ...@@ -175,52 +157,71 @@ RSpec.describe API::NpmProjectPackages do
end end
end end
context 'scoped package' do context 'valid package record' do
let(:package_name) { "@#{group.path}/my_package_name" }
let(:params) { upload_params(package_name: package_name) } let(:params) { upload_params(package_name: package_name) }
context 'with access token' do shared_examples 'handling upload with different authentications' do
subject { upload_package_with_token(package_name, params) } context 'with access token' do
subject { upload_package_with_token(package_name, params) }
it_behaves_like 'a package tracking event', 'API::NpmPackages', 'push_package'
it 'creates npm package with file' do
expect { subject }
.to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
.and change { Packages::Tag.count }.by(1)
it_behaves_like 'a package tracking event', 'API::NpmPackages', 'push_package' expect(response).to have_gitlab_http_status(:ok)
end
end
it 'creates npm package with file' do it 'creates npm package with file with job token' do
expect { subject } expect { upload_package_with_job_token(package_name, params) }
.to change { project.packages.count }.by(1) .to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1) .and change { Packages::PackageFile.count }.by(1)
.and change { Packages::Tag.count }.by(1)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
end
it 'creates npm package with file with job token' do context 'with an authenticated job token' do
expect { upload_package_with_job_token(package_name, params) } let!(:job) { create(:ci_build, user: user) }
.to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
expect(response).to have_gitlab_http_status(:ok) before do
end Grape::Endpoint.before_each do |endpoint|
expect(endpoint).to receive(:current_authenticated_job) { job }
end
end
context 'with an authenticated job token' do after do
let!(:job) { create(:ci_build, user: user) } Grape::Endpoint.before_each nil
end
before do it 'creates the package metadata' do
Grape::Endpoint.before_each do |endpoint| upload_package_with_token(package_name, params)
expect(endpoint).to receive(:current_authenticated_job) { job }
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.packages.find(json_response['id']).original_build_info.pipeline).to eq job.pipeline
end end
end end
end
after do context 'with a scoped name' do
Grape::Endpoint.before_each nil let(:package_name) { "@#{group.path}/my_package_name" }
end
it 'creates the package metadata' do it_behaves_like 'handling upload with different authentications'
upload_package_with_token(package_name, params) end
expect(response).to have_gitlab_http_status(:ok) context 'with any scoped name' do
expect(project.reload.packages.find(json_response['id']).original_build_info.pipeline).to eq job.pipeline let(:package_name) { "@any_scope/my_package_name" }
end
it_behaves_like 'handling upload with different authentications'
end
context 'with an unscoped name' do
let(:package_name) { "my_unscoped_package_name" }
it_behaves_like 'handling upload with different authentications'
end end
end end
......
...@@ -15,7 +15,7 @@ RSpec.describe Packages::Npm::CreatePackageService do ...@@ -15,7 +15,7 @@ RSpec.describe Packages::Npm::CreatePackageService do
end end
let(:override) { {} } let(:override) { {} }
let(:package_name) { "@#{namespace.path}/my-app".freeze } let(:package_name) { "@#{namespace.path}/my-app" }
subject { described_class.new(project, user, params).execute } subject { described_class.new(project, user, params).execute }
...@@ -42,29 +42,35 @@ RSpec.describe Packages::Npm::CreatePackageService do ...@@ -42,29 +42,35 @@ RSpec.describe Packages::Npm::CreatePackageService do
it { expect(subject.name).to eq(package_name) } it { expect(subject.name).to eq(package_name) }
it { expect(subject.version).to eq(version) } it { expect(subject.version).to eq(version) }
context 'with build info' do
let(:job) { create(:ci_build, user: user) }
let(:params) { super().merge(build: job) }
it_behaves_like 'assigns build to package'
it_behaves_like 'assigns status to package'
it 'creates a package file build info' do
expect { subject }.to change { Packages::PackageFileBuildInfo.count }.by(1)
end
end
end end
describe '#execute' do describe '#execute' do
context 'scoped package' do context 'scoped package' do
it_behaves_like 'valid package' it_behaves_like 'valid package'
end
context 'with build info' do context 'scoped package not following the naming convention' do
let(:job) { create(:ci_build, user: user) } let(:package_name) { '@any-scope/package' }
let(:params) { super().merge(build: job) }
it_behaves_like 'assigns build to package'
it_behaves_like 'assigns status to package'
it 'creates a package file build info' do it_behaves_like 'valid package'
expect { subject }.to change { Packages::PackageFileBuildInfo.count }.by(1)
end
end
end end
context 'invalid package name' do context 'unscoped package' do
let(:package_name) { "@#{namespace.path}/my-group/my-app".freeze } let(:package_name) { 'unscoped-package' }
it { expect { subject }.to raise_error(ActiveRecord::RecordInvalid) } it_behaves_like 'valid package'
end end
context 'package already exists' do context 'package already exists' do
...@@ -84,11 +90,18 @@ RSpec.describe Packages::Npm::CreatePackageService do ...@@ -84,11 +90,18 @@ RSpec.describe Packages::Npm::CreatePackageService do
it { expect(subject[:message]).to be 'File is too large.' } it { expect(subject[:message]).to be 'File is too large.' }
end end
context 'with incorrect namespace' do [
let(:package_name) { '@my_other_namespace/my-app' } '@inv@lid_scope/package',
'@scope/sub/group',
it 'raises a RecordInvalid error' do '@scope/../../package',
expect { subject }.to raise_error(ActiveRecord::RecordInvalid) '@scope%2e%2e%2fpackage'
].each do |invalid_package_name|
context "with invalid name #{invalid_package_name}" do
let(:package_name) { invalid_package_name }
it 'raises a RecordInvalid error' do
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
end
end end
end end
......
...@@ -22,6 +22,10 @@ RSpec.shared_context 'set package name from package name type' do ...@@ -22,6 +22,10 @@ RSpec.shared_context 'set package name from package name type' do
case package_name_type case package_name_type
when :scoped_naming_convention when :scoped_naming_convention
"@#{group.path}/scoped-package" "@#{group.path}/scoped-package"
when :scoped_no_naming_convention
'@any-scope/scoped-package'
when :unscoped
'unscoped-package'
when :non_existing when :non_existing
'non-existing-package' 'non-existing-package'
end end
......
...@@ -46,94 +46,178 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project| ...@@ -46,94 +46,178 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
end end
where(:auth, :package_name_type, :request_forward, :visibility, :user_role, :expected_result, :expected_status) do where(:auth, :package_name_type, :request_forward, :visibility, :user_role, :expected_result, :expected_status) do
nil | :scoped_naming_convention | true | 'PUBLIC' | nil | :accept | :ok nil | :scoped_naming_convention | true | :public | nil | :accept | :ok
nil | :scoped_naming_convention | false | 'PUBLIC' | nil | :accept | :ok nil | :scoped_naming_convention | false | :public | nil | :accept | :ok
nil | :non_existing | true | 'PUBLIC' | nil | :redirect | :redirected nil | :scoped_no_naming_convention | true | :public | nil | :accept | :ok
nil | :non_existing | false | 'PUBLIC' | nil | :reject | :not_found nil | :scoped_no_naming_convention | false | :public | nil | :accept | :ok
nil | :scoped_naming_convention | true | 'PRIVATE' | nil | :reject | :not_found nil | :unscoped | true | :public | nil | :accept | :ok
nil | :scoped_naming_convention | false | 'PRIVATE' | nil | :reject | :not_found nil | :unscoped | false | :public | nil | :accept | :ok
nil | :non_existing | true | 'PRIVATE' | nil | :redirect | :redirected nil | :non_existing | true | :public | nil | :redirect | :redirected
nil | :non_existing | false | 'PRIVATE' | nil | :reject | :not_found nil | :non_existing | false | :public | nil | :reject | :not_found
nil | :scoped_naming_convention | true | 'INTERNAL' | nil | :reject | :not_found nil | :scoped_naming_convention | true | :private | nil | :reject | :not_found
nil | :scoped_naming_convention | false | 'INTERNAL' | nil | :reject | :not_found nil | :scoped_naming_convention | false | :private | nil | :reject | :not_found
nil | :non_existing | true | 'INTERNAL' | nil | :redirect | :redirected nil | :scoped_no_naming_convention | true | :private | nil | :reject | :not_found
nil | :non_existing | false | 'INTERNAL' | nil | :reject | :not_found nil | :scoped_no_naming_convention | false | :private | nil | :reject | :not_found
nil | :unscoped | true | :private | nil | :reject | :not_found
:oauth | :scoped_naming_convention | true | 'PUBLIC' | :guest | :accept | :ok nil | :unscoped | false | :private | nil | :reject | :not_found
:oauth | :scoped_naming_convention | true | 'PUBLIC' | :reporter | :accept | :ok nil | :non_existing | true | :private | nil | :redirect | :redirected
:oauth | :scoped_naming_convention | false | 'PUBLIC' | :guest | :accept | :ok nil | :non_existing | false | :private | nil | :reject | :not_found
:oauth | :scoped_naming_convention | false | 'PUBLIC' | :reporter | :accept | :ok nil | :scoped_naming_convention | true | :internal | nil | :reject | :not_found
:oauth | :non_existing | true | 'PUBLIC' | :guest | :redirect | :redirected nil | :scoped_naming_convention | false | :internal | nil | :reject | :not_found
:oauth | :non_existing | true | 'PUBLIC' | :reporter | :redirect | :redirected nil | :scoped_no_naming_convention | true | :internal | nil | :reject | :not_found
:oauth | :non_existing | false | 'PUBLIC' | :guest | :reject | :not_found nil | :scoped_no_naming_convention | false | :internal | nil | :reject | :not_found
:oauth | :non_existing | false | 'PUBLIC' | :reporter | :reject | :not_found nil | :unscoped | true | :internal | nil | :reject | :not_found
:oauth | :scoped_naming_convention | true | 'PRIVATE' | :guest | :reject | :forbidden nil | :unscoped | false | :internal | nil | :reject | :not_found
:oauth | :scoped_naming_convention | true | 'PRIVATE' | :reporter | :accept | :ok nil | :non_existing | true | :internal | nil | :redirect | :redirected
:oauth | :scoped_naming_convention | false | 'PRIVATE' | :guest | :reject | :forbidden nil | :non_existing | false | :internal | nil | :reject | :not_found
:oauth | :scoped_naming_convention | false | 'PRIVATE' | :reporter | :accept | :ok
:oauth | :non_existing | true | 'PRIVATE' | :guest | :redirect | :redirected :oauth | :scoped_naming_convention | true | :public | :guest | :accept | :ok
:oauth | :non_existing | true | 'PRIVATE' | :reporter | :redirect | :redirected :oauth | :scoped_naming_convention | true | :public | :reporter | :accept | :ok
:oauth | :non_existing | false | 'PRIVATE' | :guest | :reject | :forbidden :oauth | :scoped_naming_convention | false | :public | :guest | :accept | :ok
:oauth | :non_existing | false | 'PRIVATE' | :reporter | :reject | :not_found :oauth | :scoped_naming_convention | false | :public | :reporter | :accept | :ok
:oauth | :scoped_naming_convention | true | 'INTERNAL' | :guest | :accept | :ok :oauth | :scoped_no_naming_convention | true | :public | :guest | :accept | :ok
:oauth | :scoped_naming_convention | true | 'INTERNAL' | :reporter | :accept | :ok :oauth | :scoped_no_naming_convention | true | :public | :reporter | :accept | :ok
:oauth | :scoped_naming_convention | false | 'INTERNAL' | :guest | :accept | :ok :oauth | :scoped_no_naming_convention | false | :public | :guest | :accept | :ok
:oauth | :scoped_naming_convention | false | 'INTERNAL' | :reporter | :accept | :ok :oauth | :scoped_no_naming_convention | false | :public | :reporter | :accept | :ok
:oauth | :non_existing | true | 'INTERNAL' | :guest | :redirect | :redirected :oauth | :unscoped | true | :public | :guest | :accept | :ok
:oauth | :non_existing | true | 'INTERNAL' | :reporter | :redirect | :redirected :oauth | :unscoped | true | :public | :reporter | :accept | :ok
:oauth | :non_existing | false | 'INTERNAL' | :guest | :reject | :not_found :oauth | :unscoped | false | :public | :guest | :accept | :ok
:oauth | :non_existing | false | 'INTERNAL' | :reporter | :reject | :not_found :oauth | :unscoped | false | :public | :reporter | :accept | :ok
:oauth | :non_existing | true | :public | :guest | :redirect | :redirected
:personal_access_token | :scoped_naming_convention | true | 'PUBLIC' | :guest | :accept | :ok :oauth | :non_existing | true | :public | :reporter | :redirect | :redirected
:personal_access_token | :scoped_naming_convention | true | 'PUBLIC' | :reporter | :accept | :ok :oauth | :non_existing | false | :public | :guest | :reject | :not_found
:personal_access_token | :scoped_naming_convention | false | 'PUBLIC' | :guest | :accept | :ok :oauth | :non_existing | false | :public | :reporter | :reject | :not_found
:personal_access_token | :scoped_naming_convention | false | 'PUBLIC' | :reporter | :accept | :ok :oauth | :scoped_naming_convention | true | :private | :guest | :reject | :forbidden
:personal_access_token | :non_existing | true | 'PUBLIC' | :guest | :redirect | :redirected :oauth | :scoped_naming_convention | true | :private | :reporter | :accept | :ok
:personal_access_token | :non_existing | true | 'PUBLIC' | :reporter | :redirect | :redirected :oauth | :scoped_naming_convention | false | :private | :guest | :reject | :forbidden
:personal_access_token | :non_existing | false | 'PUBLIC' | :guest | :reject | :not_found :oauth | :scoped_naming_convention | false | :private | :reporter | :accept | :ok
:personal_access_token | :non_existing | false | 'PUBLIC' | :reporter | :reject | :not_found :oauth | :scoped_no_naming_convention | true | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_naming_convention | true | 'PRIVATE' | :guest | :reject | :forbidden :oauth | :scoped_no_naming_convention | true | :private | :reporter | :accept | :ok
:personal_access_token | :scoped_naming_convention | true | 'PRIVATE' | :reporter | :accept | :ok :oauth | :scoped_no_naming_convention | false | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_naming_convention | false | 'PRIVATE' | :guest | :reject | :forbidden :oauth | :scoped_no_naming_convention | false | :private | :reporter | :accept | :ok
:personal_access_token | :scoped_naming_convention | false | 'PRIVATE' | :reporter | :accept | :ok :oauth | :unscoped | true | :private | :guest | :reject | :forbidden
:personal_access_token | :non_existing | true | 'PRIVATE' | :guest | :redirect | :redirected :oauth | :unscoped | true | :private | :reporter | :accept | :ok
:personal_access_token | :non_existing | true | 'PRIVATE' | :reporter | :redirect | :redirected :oauth | :unscoped | false | :private | :guest | :reject | :forbidden
:personal_access_token | :non_existing | false | 'PRIVATE' | :guest | :reject | :forbidden :oauth | :unscoped | false | :private | :reporter | :accept | :ok
:personal_access_token | :non_existing | false | 'PRIVATE' | :reporter | :reject | :not_found :oauth | :non_existing | true | :private | :guest | :redirect | :redirected
:personal_access_token | :scoped_naming_convention | true | 'INTERNAL' | :guest | :accept | :ok :oauth | :non_existing | true | :private | :reporter | :redirect | :redirected
:personal_access_token | :scoped_naming_convention | true | 'INTERNAL' | :reporter | :accept | :ok :oauth | :non_existing | false | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_naming_convention | false | 'INTERNAL' | :guest | :accept | :ok :oauth | :non_existing | false | :private | :reporter | :reject | :not_found
:personal_access_token | :scoped_naming_convention | false | 'INTERNAL' | :reporter | :accept | :ok :oauth | :scoped_naming_convention | true | :internal | :guest | :accept | :ok
:personal_access_token | :non_existing | true | 'INTERNAL' | :guest | :redirect | :redirected :oauth | :scoped_naming_convention | true | :internal | :reporter | :accept | :ok
:personal_access_token | :non_existing | true | 'INTERNAL' | :reporter | :redirect | :redirected :oauth | :scoped_naming_convention | false | :internal | :guest | :accept | :ok
:personal_access_token | :non_existing | false | 'INTERNAL' | :guest | :reject | :not_found :oauth | :scoped_naming_convention | false | :internal | :reporter | :accept | :ok
:personal_access_token | :non_existing | false | 'INTERNAL' | :reporter | :reject | :not_found :oauth | :scoped_no_naming_convention | true | :internal | :guest | :accept | :ok
:oauth | :scoped_no_naming_convention | true | :internal | :reporter | :accept | :ok
:job_token | :scoped_naming_convention | true | 'PUBLIC' | :developer | :accept | :ok :oauth | :scoped_no_naming_convention | false | :internal | :guest | :accept | :ok
:job_token | :scoped_naming_convention | false | 'PUBLIC' | :developer | :accept | :ok :oauth | :scoped_no_naming_convention | false | :internal | :reporter | :accept | :ok
:job_token | :non_existing | true | 'PUBLIC' | :developer | :redirect | :redirected :oauth | :unscoped | true | :internal | :guest | :accept | :ok
:job_token | :non_existing | false | 'PUBLIC' | :developer | :reject | :not_found :oauth | :unscoped | true | :internal | :reporter | :accept | :ok
:job_token | :scoped_naming_convention | true | 'PRIVATE' | :developer | :accept | :ok :oauth | :unscoped | false | :internal | :guest | :accept | :ok
:job_token | :scoped_naming_convention | false | 'PRIVATE' | :developer | :accept | :ok :oauth | :unscoped | false | :internal | :reporter | :accept | :ok
:job_token | :non_existing | true | 'PRIVATE' | :developer | :redirect | :redirected :oauth | :non_existing | true | :internal | :guest | :redirect | :redirected
:job_token | :non_existing | false | 'PRIVATE' | :developer | :reject | :not_found :oauth | :non_existing | true | :internal | :reporter | :redirect | :redirected
:job_token | :scoped_naming_convention | true | 'INTERNAL' | :developer | :accept | :ok :oauth | :non_existing | false | :internal | :guest | :reject | :not_found
:job_token | :scoped_naming_convention | false | 'INTERNAL' | :developer | :accept | :ok :oauth | :non_existing | false | :internal | :reporter | :reject | :not_found
:job_token | :non_existing | true | 'INTERNAL' | :developer | :redirect | :redirected
:job_token | :non_existing | false | 'INTERNAL' | :developer | :reject | :not_found :personal_access_token | :scoped_naming_convention | true | :public | :guest | :accept | :ok
:personal_access_token | :scoped_naming_convention | true | :public | :reporter | :accept | :ok
:deploy_token | :scoped_naming_convention | true | 'PUBLIC' | nil | :accept | :ok :personal_access_token | :scoped_naming_convention | false | :public | :guest | :accept | :ok
:deploy_token | :scoped_naming_convention | false | 'PUBLIC' | nil | :accept | :ok :personal_access_token | :scoped_naming_convention | false | :public | :reporter | :accept | :ok
:deploy_token | :non_existing | true | 'PUBLIC' | nil | :redirect | :redirected :personal_access_token | :scoped_no_naming_convention | true | :public | :guest | :accept | :ok
:deploy_token | :non_existing | false | 'PUBLIC' | nil | :reject | :not_found :personal_access_token | :scoped_no_naming_convention | true | :public | :reporter | :accept | :ok
:deploy_token | :scoped_naming_convention | true | 'PRIVATE' | nil | :accept | :ok :personal_access_token | :scoped_no_naming_convention | false | :public | :guest | :accept | :ok
:deploy_token | :scoped_naming_convention | false | 'PRIVATE' | nil | :accept | :ok :personal_access_token | :scoped_no_naming_convention | false | :public | :reporter | :accept | :ok
:deploy_token | :non_existing | true | 'PRIVATE' | nil | :redirect | :redirected :personal_access_token | :unscoped | true | :public | :guest | :accept | :ok
:deploy_token | :non_existing | false | 'PRIVATE' | nil | :reject | :not_found :personal_access_token | :unscoped | true | :public | :reporter | :accept | :ok
:deploy_token | :scoped_naming_convention | true | 'INTERNAL' | nil | :accept | :ok :personal_access_token | :unscoped | false | :public | :guest | :accept | :ok
:deploy_token | :scoped_naming_convention | false | 'INTERNAL' | nil | :accept | :ok :personal_access_token | :unscoped | false | :public | :reporter | :accept | :ok
:deploy_token | :non_existing | true | 'INTERNAL' | nil | :redirect | :redirected :personal_access_token | :non_existing | true | :public | :guest | :redirect | :redirected
:deploy_token | :non_existing | false | 'INTERNAL' | nil | :reject | :not_found :personal_access_token | :non_existing | true | :public | :reporter | :redirect | :redirected
:personal_access_token | :non_existing | false | :public | :guest | :reject | :not_found
:personal_access_token | :non_existing | false | :public | :reporter | :reject | :not_found
:personal_access_token | :scoped_naming_convention | true | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_naming_convention | true | :private | :reporter | :accept | :ok
:personal_access_token | :scoped_naming_convention | false | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_naming_convention | false | :private | :reporter | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | true | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_no_naming_convention | true | :private | :reporter | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | false | :private | :guest | :reject | :forbidden
:personal_access_token | :scoped_no_naming_convention | false | :private | :reporter | :accept | :ok
:personal_access_token | :unscoped | true | :private | :guest | :reject | :forbidden
:personal_access_token | :unscoped | true | :private | :reporter | :accept | :ok
:personal_access_token | :unscoped | false | :private | :guest | :reject | :forbidden
:personal_access_token | :unscoped | false | :private | :reporter | :accept | :ok
:personal_access_token | :non_existing | true | :private | :guest | :redirect | :redirected
:personal_access_token | :non_existing | true | :private | :reporter | :redirect | :redirected
:personal_access_token | :non_existing | false | :private | :guest | :reject | :forbidden
:personal_access_token | :non_existing | false | :private | :reporter | :reject | :not_found
:personal_access_token | :scoped_naming_convention | true | :internal | :guest | :accept | :ok
:personal_access_token | :scoped_naming_convention | true | :internal | :reporter | :accept | :ok
:personal_access_token | :scoped_naming_convention | false | :internal | :guest | :accept | :ok
:personal_access_token | :scoped_naming_convention | false | :internal | :reporter | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | true | :internal | :guest | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | true | :internal | :reporter | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | false | :internal | :guest | :accept | :ok
:personal_access_token | :scoped_no_naming_convention | false | :internal | :reporter | :accept | :ok
:personal_access_token | :unscoped | true | :internal | :guest | :accept | :ok
:personal_access_token | :unscoped | true | :internal | :reporter | :accept | :ok
:personal_access_token | :unscoped | false | :internal | :guest | :accept | :ok
:personal_access_token | :unscoped | false | :internal | :reporter | :accept | :ok
:personal_access_token | :non_existing | true | :internal | :guest | :redirect | :redirected
:personal_access_token | :non_existing | true | :internal | :reporter | :redirect | :redirected
:personal_access_token | :non_existing | false | :internal | :guest | :reject | :not_found
:personal_access_token | :non_existing | false | :internal | :reporter | :reject | :not_found
:job_token | :scoped_naming_convention | true | :public | :developer | :accept | :ok
:job_token | :scoped_naming_convention | false | :public | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | true | :public | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | false | :public | :developer | :accept | :ok
:job_token | :unscoped | true | :public | :developer | :accept | :ok
:job_token | :unscoped | false | :public | :developer | :accept | :ok
:job_token | :non_existing | true | :public | :developer | :redirect | :redirected
:job_token | :non_existing | false | :public | :developer | :reject | :not_found
:job_token | :scoped_naming_convention | true | :private | :developer | :accept | :ok
:job_token | :scoped_naming_convention | false | :private | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | true | :private | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | false | :private | :developer | :accept | :ok
:job_token | :unscoped | true | :private | :developer | :accept | :ok
:job_token | :unscoped | false | :private | :developer | :accept | :ok
:job_token | :non_existing | true | :private | :developer | :redirect | :redirected
:job_token | :non_existing | false | :private | :developer | :reject | :not_found
:job_token | :scoped_naming_convention | true | :internal | :developer | :accept | :ok
:job_token | :scoped_naming_convention | false | :internal | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | true | :internal | :developer | :accept | :ok
:job_token | :scoped_no_naming_convention | false | :internal | :developer | :accept | :ok
:job_token | :unscoped | true | :internal | :developer | :accept | :ok
:job_token | :unscoped | false | :internal | :developer | :accept | :ok
:job_token | :non_existing | true | :internal | :developer | :redirect | :redirected
:job_token | :non_existing | false | :internal | :developer | :reject | :not_found
:deploy_token | :scoped_naming_convention | true | :public | nil | :accept | :ok
:deploy_token | :scoped_naming_convention | false | :public | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | true | :public | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | false | :public | nil | :accept | :ok
:deploy_token | :unscoped | true | :public | nil | :accept | :ok
:deploy_token | :unscoped | false | :public | nil | :accept | :ok
:deploy_token | :non_existing | true | :public | nil | :redirect | :redirected
:deploy_token | :non_existing | false | :public | nil | :reject | :not_found
:deploy_token | :scoped_naming_convention | true | :private | nil | :accept | :ok
:deploy_token | :scoped_naming_convention | false | :private | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | true | :private | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | false | :private | nil | :accept | :ok
:deploy_token | :unscoped | true | :private | nil | :accept | :ok
:deploy_token | :unscoped | false | :private | nil | :accept | :ok
:deploy_token | :non_existing | true | :private | nil | :redirect | :redirected
:deploy_token | :non_existing | false | :private | nil | :reject | :not_found
:deploy_token | :scoped_naming_convention | true | :internal | nil | :accept | :ok
:deploy_token | :scoped_naming_convention | false | :internal | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | true | :internal | nil | :accept | :ok
:deploy_token | :scoped_no_naming_convention | false | :internal | nil | :accept | :ok
:deploy_token | :unscoped | true | :internal | nil | :accept | :ok
:deploy_token | :unscoped | false | :internal | nil | :accept | :ok
:deploy_token | :non_existing | true | :internal | nil | :redirect | :redirected
:deploy_token | :non_existing | false | :internal | nil | :reject | :not_found
end end
with_them do with_them do
...@@ -156,7 +240,7 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project| ...@@ -156,7 +240,7 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
before do before do
project.send("add_#{user_role}", user) if user_role project.send("add_#{user_role}", user) if user_role
project.update!(visibility: Gitlab::VisibilityLevel.const_get(visibility, false)) project.update!(visibility: visibility.to_s)
package.update!(name: package_name) unless package_name == 'non-existing-package' package.update!(name: package_name) unless package_name == 'non-existing-package'
stub_application_setting(npm_package_requests_forwarding: request_forward) stub_application_setting(npm_package_requests_forwarding: request_forward)
end end
...@@ -225,26 +309,44 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| ...@@ -225,26 +309,44 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
shared_examples 'handling different package names, visibilities and user roles' do shared_examples 'handling different package names, visibilities and user roles' do
where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
:scoped_naming_convention | 'PUBLIC' | :anonymous | :accept | :ok :scoped_naming_convention | :public | :anonymous | :accept | :ok
:scoped_naming_convention | 'PUBLIC' | :guest | :accept | :ok :scoped_naming_convention | :public | :guest | :accept | :ok
:scoped_naming_convention | 'PUBLIC' | :reporter | :accept | :ok :scoped_naming_convention | :public | :reporter | :accept | :ok
:non_existing | 'PUBLIC' | :anonymous | :reject | :not_found :scoped_no_naming_convention | :public | :anonymous | :accept | :ok
:non_existing | 'PUBLIC' | :guest | :reject | :not_found :scoped_no_naming_convention | :public | :guest | :accept | :ok
:non_existing | 'PUBLIC' | :reporter | :reject | :not_found :scoped_no_naming_convention | :public | :reporter | :accept | :ok
:unscoped | :public | :anonymous | :accept | :ok
:scoped_naming_convention | 'PRIVATE' | :anonymous | :reject | :not_found :unscoped | :public | :guest | :accept | :ok
:scoped_naming_convention | 'PRIVATE' | :guest | :reject | :forbidden :unscoped | :public | :reporter | :accept | :ok
:scoped_naming_convention | 'PRIVATE' | :reporter | :accept | :ok :non_existing | :public | :anonymous | :reject | :not_found
:non_existing | 'PRIVATE' | :anonymous | :reject | :not_found :non_existing | :public | :guest | :reject | :not_found
:non_existing | 'PRIVATE' | :guest | :reject | :forbidden :non_existing | :public | :reporter | :reject | :not_found
:non_existing | 'PRIVATE' | :reporter | :reject | :not_found
:scoped_naming_convention | :private | :anonymous | :reject | :not_found
:scoped_naming_convention | 'INTERNAL' | :anonymous | :reject | :not_found :scoped_naming_convention | :private | :guest | :reject | :forbidden
:scoped_naming_convention | 'INTERNAL' | :guest | :accept | :ok :scoped_naming_convention | :private | :reporter | :accept | :ok
:scoped_naming_convention | 'INTERNAL' | :reporter | :accept | :ok :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
:non_existing | 'INTERNAL' | :anonymous | :reject | :not_found :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
:non_existing | 'INTERNAL' | :guest | :reject | :not_found :scoped_no_naming_convention | :private | :reporter | :accept | :ok
:non_existing | 'INTERNAL' | :reporter | :reject | :not_found :unscoped | :private | :anonymous | :reject | :not_found
:unscoped | :private | :guest | :reject | :forbidden
:unscoped | :private | :reporter | :accept | :ok
:non_existing | :private | :anonymous | :reject | :not_found
:non_existing | :private | :guest | :reject | :forbidden
:non_existing | :private | :reporter | :reject | :not_found
:scoped_naming_convention | :internal | :anonymous | :reject | :not_found
:scoped_naming_convention | :internal | :guest | :accept | :ok
:scoped_naming_convention | :internal | :reporter | :accept | :ok
:scoped_no_naming_convention | :internal | :anonymous | :reject | :not_found
:scoped_no_naming_convention | :internal | :guest | :accept | :ok
:scoped_no_naming_convention | :internal | :reporter | :accept | :ok
:unscoped | :internal | :anonymous | :reject | :not_found
:unscoped | :internal | :guest | :accept | :ok
:unscoped | :internal | :reporter | :accept | :ok
:non_existing | :internal | :anonymous | :reject | :not_found
:non_existing | :internal | :guest | :reject | :not_found
:non_existing | :internal | :reporter | :reject | :not_found
end end
with_them do with_them do
...@@ -254,7 +356,7 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| ...@@ -254,7 +356,7 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
before do before do
project.send("add_#{user_role}", user) unless anonymous project.send("add_#{user_role}", user) unless anonymous
project.update!(visibility: Gitlab::VisibilityLevel.const_get(visibility, false)) project.update!(visibility: visibility.to_s)
end end
example_name = "#{params[:expected_result]} package tags request" example_name = "#{params[:expected_result]} package tags request"
...@@ -303,26 +405,44 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project| ...@@ -303,26 +405,44 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project|
shared_examples 'handling different package names, visibilities and user roles' do shared_examples 'handling different package names, visibilities and user roles' do
where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
:scoped_naming_convention | 'PUBLIC' | :anonymous | :reject | :forbidden :scoped_naming_convention | :public | :anonymous | :reject | :forbidden
:scoped_naming_convention | 'PUBLIC' | :guest | :reject | :forbidden :scoped_naming_convention | :public | :guest | :reject | :forbidden
:scoped_naming_convention | 'PUBLIC' | :developer | :accept | :ok :scoped_naming_convention | :public | :developer | :accept | :ok
:non_existing | 'PUBLIC' | :anonymous | :reject | :forbidden :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden
:non_existing | 'PUBLIC' | :guest | :reject | :forbidden :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
:non_existing | 'PUBLIC' | :developer | :reject | :not_found :scoped_no_naming_convention | :public | :developer | :accept | :ok
:unscoped | :public | :anonymous | :reject | :forbidden
:scoped_naming_convention | 'PRIVATE' | :anonymous | :reject | :not_found :unscoped | :public | :guest | :reject | :forbidden
:scoped_naming_convention | 'PRIVATE' | :guest | :reject | :forbidden :unscoped | :public | :developer | :accept | :ok
:scoped_naming_convention | 'PRIVATE' | :developer | :accept | :ok :non_existing | :public | :anonymous | :reject | :forbidden
:non_existing | 'PRIVATE' | :anonymous | :reject | :not_found :non_existing | :public | :guest | :reject | :forbidden
:non_existing | 'PRIVATE' | :guest | :reject | :forbidden :non_existing | :public | :developer | :reject | :not_found
:non_existing | 'PRIVATE' | :developer | :reject | :not_found
:scoped_naming_convention | :private | :anonymous | :reject | :not_found
:scoped_naming_convention | 'INTERNAL' | :anonymous | :reject | :forbidden :scoped_naming_convention | :private | :guest | :reject | :forbidden
:scoped_naming_convention | 'INTERNAL' | :guest | :reject | :forbidden :scoped_naming_convention | :private | :developer | :accept | :ok
:scoped_naming_convention | 'INTERNAL' | :developer | :accept | :ok :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
:non_existing | 'INTERNAL' | :anonymous | :reject | :forbidden :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
:non_existing | 'INTERNAL' | :guest | :reject | :forbidden :scoped_no_naming_convention | :private | :developer | :accept | :ok
:non_existing | 'INTERNAL' | :developer | :reject | :not_found :unscoped | :private | :anonymous | :reject | :not_found
:unscoped | :private | :guest | :reject | :forbidden
:unscoped | :private | :developer | :accept | :ok
:non_existing | :private | :anonymous | :reject | :not_found
:non_existing | :private | :guest | :reject | :forbidden
:non_existing | :private | :developer | :reject | :not_found
:scoped_naming_convention | :internal | :anonymous | :reject | :forbidden
:scoped_naming_convention | :internal | :guest | :reject | :forbidden
:scoped_naming_convention | :internal | :developer | :accept | :ok
:scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden
:scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
:scoped_no_naming_convention | :internal | :developer | :accept | :ok
:unscoped | :internal | :anonymous | :reject | :forbidden
:unscoped | :internal | :guest | :reject | :forbidden
:unscoped | :internal | :developer | :accept | :ok
:non_existing | :internal | :anonymous | :reject | :forbidden
:non_existing | :internal | :guest | :reject | :forbidden
:non_existing | :internal | :developer | :reject | :not_found
end end
with_them do with_them do
...@@ -332,7 +452,7 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project| ...@@ -332,7 +452,7 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project|
before do before do
project.send("add_#{user_role}", user) unless anonymous project.send("add_#{user_role}", user) unless anonymous
project.update!(visibility: Gitlab::VisibilityLevel.const_get(visibility, false)) project.update!(visibility: visibility.to_s)
end end
example_name = "#{params[:expected_result]} create package tag request" example_name = "#{params[:expected_result]} create package tag request"
...@@ -379,19 +499,44 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project| ...@@ -379,19 +499,44 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project|
shared_examples 'handling different package names, visibilities and user roles' do shared_examples 'handling different package names, visibilities and user roles' do
where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
:scoped_naming_convention | 'PUBLIC' | :anonymous | :reject | :forbidden :scoped_naming_convention | :public | :anonymous | :reject | :forbidden
:scoped_naming_convention | 'PUBLIC' | :guest | :reject | :forbidden :scoped_naming_convention | :public | :guest | :reject | :forbidden
:scoped_naming_convention | 'PUBLIC' | :maintainer | :accept | :ok :scoped_naming_convention | :public | :maintainer | :accept | :ok
:non_existing | 'PUBLIC' | :anonymous | :reject | :forbidden :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden
:non_existing | 'PUBLIC' | :guest | :reject | :forbidden :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
:non_existing | 'PUBLIC' | :maintainer | :reject | :not_found :scoped_no_naming_convention | :public | :maintainer | :accept | :ok
:unscoped | :public | :anonymous | :reject | :forbidden
:scoped_naming_convention | 'PRIVATE' | :anonymous | :reject | :not_found :unscoped | :public | :guest | :reject | :forbidden
:scoped_naming_convention | 'PRIVATE' | :guest | :reject | :forbidden :unscoped | :public | :maintainer | :accept | :ok
:scoped_naming_convention | 'PRIVATE' | :maintainer | :accept | :ok :non_existing | :public | :anonymous | :reject | :forbidden
:non_existing | 'INTERNAL' | :anonymous | :reject | :forbidden :non_existing | :public | :guest | :reject | :forbidden
:non_existing | 'INTERNAL' | :guest | :reject | :forbidden :non_existing | :public | :maintainer | :reject | :not_found
:non_existing | 'INTERNAL' | :maintainer | :reject | :not_found
:scoped_naming_convention | :private | :anonymous | :reject | :not_found
:scoped_naming_convention | :private | :guest | :reject | :forbidden
:scoped_naming_convention | :private | :maintainer | :accept | :ok
:scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
:scoped_no_naming_convention | :private | :guest | :reject | :forbidden
:scoped_no_naming_convention | :private | :maintainer | :accept | :ok
:unscoped | :private | :anonymous | :reject | :not_found
:unscoped | :private | :guest | :reject | :forbidden
:unscoped | :private | :maintainer | :accept | :ok
:non_existing | :private | :anonymous | :reject | :not_found
:non_existing | :private | :guest | :reject | :forbidden
:non_existing | :private | :maintainer | :reject | :not_found
:scoped_naming_convention | :internal | :anonymous | :reject | :forbidden
:scoped_naming_convention | :internal | :guest | :reject | :forbidden
:scoped_naming_convention | :internal | :maintainer | :accept | :ok
:scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden
:scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
:scoped_no_naming_convention | :internal | :maintainer | :accept | :ok
:unscoped | :internal | :anonymous | :reject | :forbidden
:unscoped | :internal | :guest | :reject | :forbidden
:unscoped | :internal | :maintainer | :accept | :ok
:non_existing | :internal | :anonymous | :reject | :forbidden
:non_existing | :internal | :guest | :reject | :forbidden
:non_existing | :internal | :maintainer | :reject | :not_found
end end
with_them do with_them do
...@@ -401,7 +546,7 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project| ...@@ -401,7 +546,7 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project|
before do before do
project.send("add_#{user_role}", user) unless anonymous project.send("add_#{user_role}", user) unless anonymous
project.update!(visibility: Gitlab::VisibilityLevel.const_get(visibility, false)) project.update!(visibility: visibility.to_s)
end end
example_name = "#{params[:expected_result]} delete package tag request" example_name = "#{params[:expected_result]} delete package tag request"
......
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