Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2e3423047a
commit
6c46be4823
|
@ -130,6 +130,7 @@ module Auth
|
|||
ContainerRepository.create_from_path!(path)
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def can_access?(requested_project, requested_action)
|
||||
return false unless requested_project.container_registry_enabled?
|
||||
return false if requested_project.repository_access_level == ::ProjectFeature::DISABLED
|
||||
|
@ -226,11 +227,16 @@ module Auth
|
|||
end
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def extra_info
|
||||
{}
|
||||
end
|
||||
|
||||
def log_if_actions_denied(type, requested_project, requested_actions, authorized_actions)
|
||||
return if requested_actions == authorized_actions
|
||||
|
||||
log_info = {
|
||||
message: "Denied container registry permissions",
|
||||
message: 'Denied container registry permissions',
|
||||
scope_type: type,
|
||||
requested_project_path: requested_project.full_path,
|
||||
requested_actions: requested_actions,
|
||||
|
@ -238,9 +244,11 @@ module Auth
|
|||
username: current_user&.username,
|
||||
user_id: current_user&.id,
|
||||
project_path: project&.full_path
|
||||
}.compact
|
||||
}.merge!(extra_info).compact
|
||||
|
||||
Gitlab::AuthLogger.warn(log_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Auth::ContainerRegistryAuthenticationService.prepend_if_ee('EE::Auth::ContainerRegistryAuthenticationService')
|
||||
|
|
|
@ -1386,7 +1386,7 @@ test:
|
|||
storages:
|
||||
default:
|
||||
path: tmp/tests/repositories/
|
||||
gitaly_address: unix:tmp/tests/gitaly/gitaly.socket
|
||||
gitaly_address: unix:tmp/tests/gitaly/praefect.socket
|
||||
|
||||
gitaly:
|
||||
client_path: tmp/tests/gitaly
|
||||
|
|
|
@ -13,8 +13,9 @@ ignorecase: true
|
|||
swap:
|
||||
active user: '"billable user"'
|
||||
active users: '"billable users"'
|
||||
since: '"because" or "after"'
|
||||
docs: documentation
|
||||
once that: '"after that"'
|
||||
once the: '"after the"'
|
||||
once you: '"after you"'
|
||||
since: '"because" or "after"'
|
||||
within: '"in"'
|
||||
|
|
|
@ -316,6 +316,37 @@ rspec:
|
|||
- rspec spec
|
||||
```
|
||||
|
||||
If you have jobs that each need a different selection of gems, use the `prefix`
|
||||
keyword in the global `cache` definition. This configuration generates a different
|
||||
cache for each job.
|
||||
|
||||
For example, a testing job might not need the same gems as a job that deploys to
|
||||
production:
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- Gemfile.lock
|
||||
prefix: ${CI_JOB_NAME}
|
||||
paths:
|
||||
- vendor/ruby
|
||||
|
||||
test_job:
|
||||
stage: test
|
||||
before_script:
|
||||
- bundle install --without production --path vendor/ruby
|
||||
script:
|
||||
- bundle exec rspec
|
||||
|
||||
deploy_job:
|
||||
stage: production
|
||||
before_script:
|
||||
- bundle install --without test --path vendor/ruby
|
||||
script:
|
||||
- bundle exec deploy
|
||||
```
|
||||
|
||||
### Caching Go dependencies
|
||||
|
||||
Assuming your project is using [Go Modules](https://github.com/golang/go/wiki/Modules) to install
|
||||
|
|
|
@ -19,14 +19,14 @@ in your existing `.gitlab-ci.yml` file or by implicitly using
|
|||
[Auto License Compliance](../../../topics/autodevops/stages.md#auto-license-compliance)
|
||||
that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
|
||||
|
||||
GitLab checks the License Compliance report, compares the licenses between the
|
||||
source and target branches, and shows the information right on the merge request.
|
||||
Denied licenses are notated with an `x` red icon next to them
|
||||
as well as new licenses which need a decision from you. In addition, you can
|
||||
[manually allow or deny](#policies)
|
||||
licenses in your project's license compliance policy section. If GitLab detects a denied license
|
||||
in a new commit, GitLab blocks any merge requests containing that commit and instructs the developer
|
||||
to remove the license.
|
||||
The [License Finder](https://github.com/pivotal/LicenseFinder) scan tool runs as part of the CI/CD
|
||||
pipeline, and detects the licenses in use. GitLab checks the License Compliance report, compares the
|
||||
licenses between the source and target branches, and shows the information right on the merge
|
||||
request. Denied licenses are indicated by a `x` red icon next to them as well as new licenses that
|
||||
need a decision from you. In addition, you can [manually allow or deny](#policies) licenses in your
|
||||
project's license compliance policy section. If a denied license is detected in a new commit,
|
||||
GitLab blocks any merge requests containing that commit and instructs the developer to remove the
|
||||
license.
|
||||
|
||||
NOTE:
|
||||
If the license compliance report doesn't have anything to compare to, no information
|
||||
|
@ -51,36 +51,33 @@ You can view and modify existing policies from the [policies](#policies) tab.
|
|||
|
||||
The following languages and package managers are supported.
|
||||
|
||||
| Language | Package managers | Notes | Scan Tool |
|
||||
|------------|------------------|-------|-----------|
|
||||
| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/) | | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| Go | [Godep](https://github.com/tools/godep), [go mod](https://github.com/golang/go/wiki/Modules) | | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) | | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| .NET | [Nuget](https://www.nuget.org/) | The .NET Framework is supported via the [mono project](https://www.mono-project.com/). There are, however, some limitations. The scanner doesn't support Windows-specific dependencies and doesn't report dependencies of your project's listed dependencies. Also, the scanner always marks detected licenses for all dependencies as `unknown`. | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| Python | [pip](https://pip.pypa.io/en/stable/) | Python is supported through [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock). | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| Ruby | [gem](https://rubygems.org/) | | [License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
Java 8 and Gradle 1.x projects are not supported. The minimum supported version of Maven is 3.2.5.
|
||||
|
||||
NOTE:
|
||||
Java 8 and Gradle 1.x projects are not supported.
|
||||
The minimum supported version of Maven is 3.2.5.
|
||||
| Language | Package managers | Notes |
|
||||
|------------|----------------------------------------------------------------------------------------------|-------|
|
||||
| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/) | |
|
||||
| Go | [Godep](https://github.com/tools/godep), [go mod](https://github.com/golang/go/wiki/Modules) | |
|
||||
| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) | |
|
||||
| .NET | [Nuget](https://www.nuget.org/) | The .NET Framework is supported via the [mono project](https://www.mono-project.com/). There are, however, some limitations. The scanner doesn't support Windows-specific dependencies and doesn't report dependencies of your project's listed dependencies. Also, the scanner always marks detected licenses for all dependencies as `unknown`. |
|
||||
| Python | [pip](https://pip.pypa.io/en/stable/) | Python is supported through [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock). |
|
||||
| Ruby | [gem](https://rubygems.org/) | |
|
||||
|
||||
### Experimental support
|
||||
|
||||
The following languages and package managers are [supported experimentally](https://github.com/pivotal/LicenseFinder#experimental-project-types),
|
||||
which means that the reported licenses might be incomplete or inaccurate.
|
||||
The following languages and package managers are [supported experimentally](https://github.com/pivotal/LicenseFinder#experimental-project-types).
|
||||
The reported licenses might be incomplete or inaccurate.
|
||||
|
||||
| Language | Package managers | Scan Tool |
|
||||
|------------|-------------------------------------------------------------------|----------------------------------------------------------|
|
||||
| JavaScript | [Yarn](https://yarnpkg.com/)|[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Go | go get, gvt, glide, dep, trash, govendor |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Erlang | [Rebar](https://www.rebar3.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) | [License Finder](https://github.com/pivotal/LicenseFinder) |
|
||||
| Objective-C, Swift | [CocoaPods](https://cocoapods.org/) v0.39 and below |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Elixir | [Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| C++/C | [Conan](https://conan.io/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Scala | [sbt](https://www.scala-sbt.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Rust | [Cargo](https://crates.io) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| PHP | [Composer](https://getcomposer.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
|
||||
| Language | Package managers |
|
||||
|------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| JavaScript | [Yarn](https://yarnpkg.com/) |
|
||||
| Go | go get, gvt, glide, dep, trash, govendor |
|
||||
| Erlang | [Rebar](https://www.rebar3.org/) |
|
||||
| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage), [CocoaPods](https://cocoapods.org/) v0.39 and below |
|
||||
| Elixir | [Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) |
|
||||
| C++/C | [Conan](https://conan.io/) |
|
||||
| Scala | [sbt](https://www.scala-sbt.org/) |
|
||||
| Rust | [Cargo](https://crates.io) |
|
||||
| PHP | [Composer](https://getcomposer.org/) |
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
@ -288,7 +288,7 @@ below.
|
|||
|
||||
WARNING:
|
||||
Interactive Web Terminals for the Web IDE is currently in **Beta**.
|
||||
Shared runners [do not yet support Interactive Web Terminals](https://gitlab.com/gitlab-org/gitlab/-/issues/24674),
|
||||
GitLab.com shared runners [do not yet support Interactive Web Terminals](https://gitlab.com/gitlab-org/gitlab/-/issues/24674),
|
||||
so you would need to use your own private runner to make use of this feature.
|
||||
|
||||
[Interactive Web Terminals](../../../ci/interactive_web_terminal/index.md)
|
||||
|
|
|
@ -4,10 +4,10 @@ require 'toml-rb'
|
|||
|
||||
module Gitlab
|
||||
module SetupHelper
|
||||
def create_configuration(dir, storage_paths, force: false)
|
||||
def create_configuration(dir, storage_paths, force: false, options: {})
|
||||
generate_configuration(
|
||||
configuration_toml(dir, storage_paths),
|
||||
get_config_path(dir),
|
||||
configuration_toml(dir, storage_paths, options),
|
||||
get_config_path(dir, options),
|
||||
force: force
|
||||
)
|
||||
end
|
||||
|
@ -31,7 +31,7 @@ module Gitlab
|
|||
module Workhorse
|
||||
extend Gitlab::SetupHelper
|
||||
class << self
|
||||
def configuration_toml(dir, _)
|
||||
def configuration_toml(dir, _, _)
|
||||
config = { redis: { URL: redis_url } }
|
||||
|
||||
TomlRB.dump(config)
|
||||
|
@ -41,8 +41,8 @@ module Gitlab
|
|||
Gitlab::Redis::SharedState.url
|
||||
end
|
||||
|
||||
def get_config_path(dir)
|
||||
File.join(dir, 'config.toml')
|
||||
def get_config_path(dir, _)
|
||||
File.join(dir, 'config_path')
|
||||
end
|
||||
|
||||
def compile_into(dir)
|
||||
|
@ -76,7 +76,7 @@ module Gitlab
|
|||
# because it uses a Unix socket.
|
||||
# For development and testing purposes, an extra storage is added to gitaly,
|
||||
# which is not known to Rails, but must be explicitly stubbed.
|
||||
def configuration_toml(gitaly_dir, storage_paths, gitaly_ruby: true)
|
||||
def configuration_toml(gitaly_dir, storage_paths, options, gitaly_ruby: true)
|
||||
storages = []
|
||||
address = nil
|
||||
|
||||
|
@ -97,14 +97,20 @@ module Gitlab
|
|||
config = { socket_path: address.sub(/\Aunix:/, '') }
|
||||
|
||||
if Rails.env.test?
|
||||
socket_filename = options[:gitaly_socket] || "gitaly.socket"
|
||||
|
||||
config = {
|
||||
# Override the set gitaly_address since Praefect is in the loop
|
||||
socket_path: File.join(gitaly_dir, socket_filename),
|
||||
auth: { token: 'secret' },
|
||||
# Compared to production, tests run in constrained environments. This
|
||||
# number is meant to grow with the number of concurrent rails requests /
|
||||
# sidekiq jobs, and concurrency will be low anyway in test.
|
||||
git: { catfile_cache_size: 5 }
|
||||
}
|
||||
|
||||
storage_path = Rails.root.join('tmp', 'tests', 'second_storage').to_s
|
||||
storages << { name: 'test_second_storage', path: storage_path }
|
||||
|
||||
config[:auth] = { token: 'secret' }
|
||||
# Compared to production, tests run in constrained environments. This
|
||||
# number is meant to grow with the number of concurrent rails requests /
|
||||
# sidekiq jobs, and concurrency will be low anyway in test.
|
||||
config[:git] = { catfile_cache_size: 5 }
|
||||
end
|
||||
|
||||
config[:storage] = storages
|
||||
|
@ -124,8 +130,9 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def get_config_path(dir)
|
||||
File.join(dir, 'config.toml')
|
||||
def get_config_path(dir, options)
|
||||
config_filename = options[:config_filename] || 'config.toml'
|
||||
File.join(dir, config_filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -133,9 +140,11 @@ module Gitlab
|
|||
module Praefect
|
||||
extend Gitlab::SetupHelper
|
||||
class << self
|
||||
def configuration_toml(gitaly_dir, storage_paths)
|
||||
def configuration_toml(gitaly_dir, _, _)
|
||||
nodes = [{ storage: 'default', address: "unix:#{gitaly_dir}/gitaly.socket", primary: true, token: 'secret' }]
|
||||
storages = [{ name: 'default', node: nodes }]
|
||||
second_storage_nodes = [{ storage: 'test_second_storage', address: "unix:#{gitaly_dir}/gitaly2.socket", primary: true, token: 'secret' }]
|
||||
|
||||
storages = [{ name: 'default', node: nodes }, { name: 'test_second_storage', node: second_storage_nodes }]
|
||||
failover = { enabled: false }
|
||||
config = { socket_path: "#{gitaly_dir}/praefect.socket", memory_queue_enabled: true, virtual_storage: storages, failover: failover }
|
||||
config[:token] = 'secret' if Rails.env.test?
|
||||
|
@ -145,7 +154,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def get_config_path(dir)
|
||||
def get_config_path(dir, _)
|
||||
File.join(dir, 'praefect.config.toml')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,8 +19,10 @@ class GitalyTestBuild
|
|||
|
||||
# Starting gitaly further validates its configuration
|
||||
gitaly_pid = start_gitaly
|
||||
gitaly2_pid = start_gitaly2
|
||||
praefect_pid = start_praefect
|
||||
Process.kill('TERM', gitaly_pid)
|
||||
Process.kill('TERM', gitaly2_pid)
|
||||
Process.kill('TERM', praefect_pid)
|
||||
|
||||
# Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'.
|
||||
|
|
|
@ -15,6 +15,7 @@ class GitalyTestSpawn
|
|||
|
||||
# In local development this pid file is used by rspec.
|
||||
IO.write(File.expand_path('../tmp/tests/gitaly.pid', __dir__), start_gitaly)
|
||||
IO.write(File.expand_path('../tmp/tests/gitaly2.pid', __dir__), start_gitaly2)
|
||||
IO.write(File.expand_path('../tmp/tests/praefect.pid', __dir__), start_praefect)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,21 +62,36 @@ module GitalyTest
|
|||
case service
|
||||
when :gitaly
|
||||
File.join(tmp_tests_gitaly_dir, 'config.toml')
|
||||
when :gitaly2
|
||||
File.join(tmp_tests_gitaly_dir, 'gitaly2.config.toml')
|
||||
when :praefect
|
||||
File.join(tmp_tests_gitaly_dir, 'praefect.config.toml')
|
||||
end
|
||||
end
|
||||
|
||||
def service_binary(service)
|
||||
case service
|
||||
when :gitaly, :gitaly2
|
||||
'gitaly'
|
||||
when :praefect
|
||||
'praefect'
|
||||
end
|
||||
end
|
||||
|
||||
def start_gitaly
|
||||
start(:gitaly)
|
||||
end
|
||||
|
||||
def start_gitaly2
|
||||
start(:gitaly2)
|
||||
end
|
||||
|
||||
def start_praefect
|
||||
start(:praefect)
|
||||
end
|
||||
|
||||
def start(service)
|
||||
args = ["#{tmp_tests_gitaly_dir}/#{service}"]
|
||||
args = ["#{tmp_tests_gitaly_dir}/#{service_binary(service)}"]
|
||||
args.push("-config") if service == :praefect
|
||||
args.push(config_path(service))
|
||||
pid = spawn(env, *args, [:out, :err] => "log/#{service}-test.log")
|
||||
|
|
|
@ -5,993 +5,5 @@ require 'spec_helper'
|
|||
RSpec.describe Auth::ContainerRegistryAuthenticationService do
|
||||
include AdminModeHelper
|
||||
|
||||
let(:current_project) { nil }
|
||||
let(:current_user) { nil }
|
||||
let(:current_params) { {} }
|
||||
let(:rsa_key) { OpenSSL::PKey::RSA.generate(512) }
|
||||
let(:payload) { JWT.decode(subject[:token], rsa_key, true, { algorithm: 'RS256' }).first }
|
||||
|
||||
let(:authentication_abilities) do
|
||||
[:read_container_image, :create_container_image, :admin_container_image]
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new(current_project, current_user, current_params)
|
||||
.execute(authentication_abilities: authentication_abilities)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Gitlab.config.registry).to receive_messages(enabled: true, issuer: 'rspec', key: nil)
|
||||
allow_next_instance_of(JSONWebToken::RSAToken) do |instance|
|
||||
allow(instance).to receive(:key).and_return(rsa_key)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an authenticated' do
|
||||
it { is_expected.to include(:token) }
|
||||
it { expect(payload).to include('access') }
|
||||
end
|
||||
|
||||
shared_examples 'a valid token' do
|
||||
it { is_expected.to include(:token) }
|
||||
it { expect(payload).to include('access') }
|
||||
|
||||
context 'a expirable' do
|
||||
let(:expires_at) { Time.zone.at(payload['exp']) }
|
||||
let(:expire_delay) { 10 }
|
||||
|
||||
context 'for default configuration' do
|
||||
it { expect(expires_at).not_to be_within(2.seconds).of(Time.current + expire_delay.minutes) }
|
||||
end
|
||||
|
||||
context 'for changed configuration' do
|
||||
before do
|
||||
stub_application_setting(container_registry_token_expire_delay: expire_delay)
|
||||
end
|
||||
|
||||
it { expect(expires_at).to be_within(2.seconds).of(Time.current + expire_delay.minutes) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a browsable' do
|
||||
let(:access) do
|
||||
[{ 'type' => 'registry',
|
||||
'name' => 'catalog',
|
||||
'actions' => ['*'] }]
|
||||
end
|
||||
|
||||
it_behaves_like 'a valid token'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
|
||||
it 'has the correct scope' do
|
||||
expect(payload).to include('access' => access)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an accessible' do
|
||||
let(:access) do
|
||||
[{ 'type' => 'repository',
|
||||
'name' => project.full_path,
|
||||
'actions' => actions }]
|
||||
end
|
||||
|
||||
it_behaves_like 'a valid token'
|
||||
|
||||
it 'has the correct scope' do
|
||||
expect(payload).to include('access' => access)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'an inaccessible' do
|
||||
it_behaves_like 'a valid token'
|
||||
it { expect(payload).to include('access' => []) }
|
||||
end
|
||||
|
||||
shared_examples 'a deletable' do
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['*'] }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a deletable since registry 2.7' do
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['delete'] }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a pullable' do
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['pull'] }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a pushable' do
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['push'] }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a pullable and pushable' do
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { %w(pull push) }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'a forbidden' do
|
||||
it { is_expected.to include(http_status: 403) }
|
||||
it { is_expected.not_to include(:token) }
|
||||
end
|
||||
|
||||
shared_examples 'container repository factory' do
|
||||
it 'creates a new container repository resource' do
|
||||
expect { subject }
|
||||
.to change { project.container_repositories.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'not a container repository factory' do
|
||||
it 'does not create a new container repository resource' do
|
||||
expect { subject }.not_to change { ContainerRepository.count }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#full_access_token' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let(:token) { described_class.full_access_token(project.full_path) }
|
||||
|
||||
subject { { token: token } }
|
||||
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['*'] }
|
||||
end
|
||||
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
describe '#pull_access_token' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let(:token) { described_class.pull_access_token(project.full_path) }
|
||||
|
||||
subject { { token: token } }
|
||||
|
||||
it_behaves_like 'an accessible' do
|
||||
let(:actions) { ['pull'] }
|
||||
end
|
||||
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'user authorization' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
context 'for registry catalog' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["registry:catalog:*"] }
|
||||
end
|
||||
|
||||
context 'disallow browsing for users without GitLab admin rights' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
context 'allow to use scope-less authentication' do
|
||||
it_behaves_like 'a valid token'
|
||||
end
|
||||
|
||||
context 'allow developer to push images' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pushable'
|
||||
it_behaves_like 'container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow developer to delete images' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
|
||||
it 'logs an auth warning' do
|
||||
expect(Gitlab::AuthLogger).to receive(:warn).with(
|
||||
message: 'Denied container registry permissions',
|
||||
scope_type: 'repository',
|
||||
requested_project_path: project.full_path,
|
||||
requested_actions: ['*'],
|
||||
authorized_actions: [],
|
||||
user_id: current_user.id,
|
||||
username: current_user.username
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'disallow developer to delete images since registry 2.7' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'allow reporter to pull images' do
|
||||
before_all do
|
||||
project.add_reporter(current_user)
|
||||
end
|
||||
|
||||
context 'when pulling from root level repository' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'disallow reporter to delete images' do
|
||||
before_all do
|
||||
project.add_reporter(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow reporter to delete images since registry 2.7' do
|
||||
before_all do
|
||||
project.add_reporter(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'return a least of privileges' do
|
||||
before_all do
|
||||
project.add_reporter(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push,pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow guest to pull or push images' do
|
||||
before_all do
|
||||
project.add_guest(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull,push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow guest to delete images' do
|
||||
before_all do
|
||||
project.add_guest(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow guest to delete images since registry 2.7' do
|
||||
before_all do
|
||||
project.add_guest(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
context 'allow anyone to pull images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to push images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images since registry 2.7' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when repository name is invalid' do
|
||||
let(:current_params) do
|
||||
{ scopes: ['repository:invalid:push'] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for internal project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'for internal user' do
|
||||
context 'allow anyone to pull images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to push images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images since registry 2.7' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for external user' do
|
||||
context 'disallow anyone to pull or push images' do
|
||||
let_it_be(:current_user) { create(:user, external: true) }
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull,push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images' do
|
||||
let_it_be(:current_user) { create(:user, external: true) }
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'disallow anyone to delete images since registry 2.7' do
|
||||
let_it_be(:current_user) { create(:user, external: true) }
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'delete authorized as maintainer' do
|
||||
let_it_be(:current_project) { create(:project) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:authentication_abilities) do
|
||||
[:admin_container_image]
|
||||
end
|
||||
|
||||
before_all do
|
||||
current_project.add_maintainer(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'a valid token'
|
||||
|
||||
context 'allow to delete images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{current_project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a deletable' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
end
|
||||
|
||||
context 'allow to delete images since registry 2.7' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{current_project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a deletable since registry 2.7' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'build authorized as user' do
|
||||
let_it_be(:current_project) { create(:project) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:authentication_abilities) do
|
||||
[:build_read_container_image, :build_create_container_image, :build_destroy_container_image]
|
||||
end
|
||||
|
||||
before_all do
|
||||
current_project.add_developer(current_user)
|
||||
end
|
||||
|
||||
context 'allow to use offline_token' do
|
||||
let(:current_params) do
|
||||
{ offline_token: true }
|
||||
end
|
||||
|
||||
it_behaves_like 'an authenticated'
|
||||
end
|
||||
|
||||
it_behaves_like 'a valid token'
|
||||
|
||||
context 'allow to pull and push images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{current_project.full_path}:pull,push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable and pushable' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
|
||||
it_behaves_like 'container repository factory' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
end
|
||||
|
||||
context 'allow to delete images since registry 2.7' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{current_project.full_path}:delete"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a deletable since registry 2.7' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
end
|
||||
|
||||
context 'disallow to delete images' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{current_project.full_path}:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible' do
|
||||
let(:project) { current_project }
|
||||
end
|
||||
end
|
||||
|
||||
context 'for other projects' do
|
||||
context 'when pulling' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
context 'allow for public' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
shared_examples 'pullable for being team member' do
|
||||
context 'when you are not member' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when you are member' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when you are owner' do
|
||||
let_it_be(:project) { create(:project, namespace: current_user.namespace) }
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for private' do
|
||||
let_it_be(:project) { create(:project, :private) }
|
||||
|
||||
it_behaves_like 'pullable for being team member'
|
||||
|
||||
context 'when you are admin' do
|
||||
let_it_be(:current_user) { create(:admin) }
|
||||
|
||||
context 'when you are not member' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when you are member' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when you are owner' do
|
||||
let_it_be(:project) { create(:project, namespace: current_user.namespace) }
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
context 'disallow for all' do
|
||||
context 'when you are member' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when you are owner' do
|
||||
let_it_be(:project) { create(:project, :public, namespace: current_user.namespace) }
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for project without container registry' do
|
||||
let_it_be(:project) { create(:project, :public, container_registry_enabled: false) }
|
||||
|
||||
before do
|
||||
project.update!(container_registry_enabled: false)
|
||||
end
|
||||
|
||||
context 'disallow when pulling' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for project that disables repository' do
|
||||
let_it_be(:project) { create(:project, :public, :repository_disabled) }
|
||||
|
||||
context 'disallow when pulling' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'registry catalog browsing authorized as admin' do
|
||||
let_it_be(:current_user) { create(:user, :admin) }
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["registry:catalog:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a browsable'
|
||||
end
|
||||
|
||||
context 'support for multiple scopes' do
|
||||
let_it_be(:internal_project) { create(:project, :internal) }
|
||||
let_it_be(:private_project) { create(:project, :private) }
|
||||
|
||||
let(:current_params) do
|
||||
{
|
||||
scopes: [
|
||||
"repository:#{internal_project.full_path}:pull",
|
||||
"repository:#{private_project.full_path}:pull"
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
context 'user has access to all projects' do
|
||||
let_it_be(:current_user) { create(:user, :admin) }
|
||||
|
||||
before do
|
||||
enable_admin_mode!(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'a browsable' do
|
||||
let(:access) do
|
||||
[
|
||||
{ 'type' => 'repository',
|
||||
'name' => internal_project.full_path,
|
||||
'actions' => ['pull'] },
|
||||
{ 'type' => 'repository',
|
||||
'name' => private_project.full_path,
|
||||
'actions' => ['pull'] }
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user only has access to internal project' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
it_behaves_like 'a browsable' do
|
||||
let(:access) do
|
||||
[
|
||||
{ 'type' => 'repository',
|
||||
'name' => internal_project.full_path,
|
||||
'actions' => ['pull'] }
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'anonymous access is rejected' do
|
||||
let(:current_user) { nil }
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'unauthorized' do
|
||||
context 'disallow to use scope-less authentication' do
|
||||
it_behaves_like 'a forbidden'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'for invalid scope' do
|
||||
let(:current_params) do
|
||||
{ scopes: ['invalid:aa:bb'] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project, :private) }
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
end
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
context 'when pulling and pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull,push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
|
||||
context 'when pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for registry catalog' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["registry:catalog:*"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
it_behaves_like 'not a container repository factory'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for deploy tokens' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:pull"] }
|
||||
end
|
||||
|
||||
context 'when deploy token has read and write registry as scopes' do
|
||||
let(:current_user) { create(:deploy_token, write_registry: true, projects: [project]) }
|
||||
|
||||
shared_examples 'able to login' do
|
||||
context 'registry provides read_container_image authentication_abilities' do
|
||||
let(:current_params) { {} }
|
||||
let(:authentication_abilities) { [:read_container_image] }
|
||||
|
||||
it_behaves_like 'an authenticated'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
|
||||
context 'when pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pushable'
|
||||
end
|
||||
|
||||
it_behaves_like 'able to login'
|
||||
end
|
||||
|
||||
context 'for internal project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
|
||||
context 'when pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pushable'
|
||||
end
|
||||
|
||||
it_behaves_like 'able to login'
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project, :private) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
|
||||
context 'when pushing' do
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pushable'
|
||||
end
|
||||
|
||||
it_behaves_like 'able to login'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when deploy token does not have read_registry scope' do
|
||||
let(:current_user) { create(:deploy_token, projects: [project], read_registry: false) }
|
||||
|
||||
shared_examples 'unable to login' do
|
||||
context 'registry provides no container authentication_abilities' do
|
||||
let(:current_params) { {} }
|
||||
let(:authentication_abilities) { [] }
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
end
|
||||
|
||||
context 'registry provides inapplicable container authentication_abilities' do
|
||||
let(:current_params) { {} }
|
||||
let(:authentication_abilities) { [:download_code] }
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
|
||||
it_behaves_like 'unable to login'
|
||||
end
|
||||
|
||||
context 'for internal project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
|
||||
it_behaves_like 'unable to login'
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
|
||||
context 'when logging in' do
|
||||
let(:current_params) { {} }
|
||||
let(:authentication_abilities) { [] }
|
||||
|
||||
it_behaves_like 'a forbidden'
|
||||
end
|
||||
|
||||
it_behaves_like 'unable to login'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when deploy token is not related to the project' do
|
||||
let_it_be(:current_user) { create(:deploy_token, read_registry: false) }
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for internal project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
context 'when pulling' do
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when deploy token has been revoked' do
|
||||
let(:current_user) { create(:deploy_token, :revoked, projects: [project]) }
|
||||
|
||||
context 'for public project' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
it_behaves_like 'a pullable'
|
||||
end
|
||||
|
||||
context 'for internal project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
|
||||
context 'for private project' do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
|
||||
it_behaves_like 'an inaccessible'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user authorization' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
context 'with multiple scopes' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
context 'allow developer to push images' do
|
||||
before_all do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
let(:current_params) do
|
||||
{ scopes: ["repository:#{project.full_path}:push"] }
|
||||
end
|
||||
|
||||
it_behaves_like 'a pushable'
|
||||
it_behaves_like 'container repository factory'
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like 'a container registry auth service'
|
||||
end
|
||||
|
|
|
@ -168,6 +168,11 @@ module TestEnv
|
|||
version: Gitlab::GitalyClient.expected_server_version,
|
||||
task: "gitlab:gitaly:install[#{install_gitaly_args}]") do
|
||||
Gitlab::SetupHelper::Gitaly.create_configuration(gitaly_dir, { 'default' => repos_path }, force: true)
|
||||
Gitlab::SetupHelper::Gitaly.create_configuration(
|
||||
gitaly_dir,
|
||||
{ 'default' => repos_path }, force: true,
|
||||
options: { gitaly_socket: "gitaly2.socket", config_filename: "gitaly2.config.toml" }
|
||||
)
|
||||
Gitlab::SetupHelper::Praefect.create_configuration(gitaly_dir, { 'praefect' => repos_path }, force: true)
|
||||
end
|
||||
|
||||
|
@ -283,7 +288,7 @@ module TestEnv
|
|||
host = "[#{host}]" if host.include?(':')
|
||||
listen_addr = [host, port].join(':')
|
||||
|
||||
config_path = Gitlab::SetupHelper::Workhorse.get_config_path(workhorse_dir)
|
||||
config_path = Gitlab::SetupHelper::Workhorse.get_config_path(workhorse_dir, {})
|
||||
|
||||
# This should be set up in setup_workhorse, but since
|
||||
# component_needs_update? only checks that versions are consistent,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue