Commit 9398d718 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 602ea426
......@@ -114,7 +114,7 @@ module Groups
end
def deploy_token_params
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :username)
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
end
end
end
......
......@@ -93,7 +93,7 @@ module Projects
end
def deploy_token_params
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :username)
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
end
def run_autodevops_pipeline(service)
......
......@@ -7,7 +7,7 @@ class DeployToken < ApplicationRecord
include Gitlab::Utils::StrongMemoize
add_authentication_token_field :token, encrypted: :optional
AVAILABLE_SCOPES = %i(read_repository read_registry).freeze
AVAILABLE_SCOPES = %i(read_repository read_registry write_registry).freeze
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'
default_value_for(:expires_at) { Forever.date }
......@@ -105,7 +105,7 @@ class DeployToken < ApplicationRecord
end
def ensure_at_least_one_scope
errors.add(:base, _("Scopes can't be blank")) unless read_repository || read_registry
errors.add(:base, _("Scopes can't be blank")) unless read_repository || read_registry || write_registry
end
def default_username
......
......@@ -135,7 +135,7 @@ module Auth
when 'pull'
build_can_pull?(requested_project) || user_can_pull?(requested_project) || deploy_token_can_pull?(requested_project)
when 'push'
build_can_push?(requested_project) || user_can_push?(requested_project)
build_can_push?(requested_project) || user_can_push?(requested_project) || deploy_token_can_push?(requested_project)
when 'delete'
build_can_delete?(requested_project) || user_can_admin?(requested_project)
when '*'
......@@ -185,6 +185,13 @@ module Auth
current_user.read_registry?
end
def deploy_token_can_push?(requested_project)
has_authentication_ability?(:create_container_image) &&
current_user.is_a?(DeployToken) &&
current_user.has_access_to?(requested_project) &&
current_user.write_registry?
end
##
# We still support legacy pipeline triggers which do not have associated
# actor. New permissions model and new triggers are always associated with
......
......@@ -5,12 +5,15 @@ module Projects
include Gitlab::ShellAdapter
Error = Class.new(StandardError)
SameFilesystemError = Class.new(Error)
def initialize(project)
@project = project
end
def execute(new_repository_storage_key)
raise SameFilesystemError if same_filesystem?(project.repository.storage, new_repository_storage_key)
mirror_repositories(new_repository_storage_key)
mark_old_paths_for_archive
......@@ -33,6 +36,10 @@ module Projects
private
def same_filesystem?(old_storage, new_storage)
Gitlab::GitalyClient.filesystem_id(old_storage) == Gitlab::GitalyClient.filesystem_id(new_storage)
end
def mirror_repositories(new_repository_storage_key)
mirror_repository(new_repository_storage_key)
......
......@@ -4,7 +4,7 @@
- expanded = expanded_by_default?
- general_expanded = @project.errors.empty? ? expanded : true
- deploy_token_description = s_('DeployTokens|Deploy tokens allow read-only access to your repository and registry images.')
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to your repository and registry images.')
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded) }
.settings-header
......
......@@ -30,5 +30,10 @@
= label_tag ("deploy_token_read_registry"), 'read_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows read-only access to the registry images')
%fieldset.form-group.form-check
= f.check_box :write_registry, class: 'form-check-input'
= label_tag ("deploy_token_write_registry"), 'write_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows write access to the registry images')
.prepend-top-default
= f.submit s_('DeployTokens|Create deploy token'), class: 'btn btn-success qa-create-deploy-token'
......@@ -3,21 +3,11 @@
class ProjectUpdateRepositoryStorageWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
SameFilesystemError = Class.new(StandardError)
feature_category :gitaly
def perform(project_id, new_repository_storage_key)
project = Project.find(project_id)
raise SameFilesystemError if same_filesystem?(project.repository.storage, new_repository_storage_key)
::Projects::UpdateRepositoryStorageService.new(project).execute(new_repository_storage_key)
end
private
def same_filesystem?(old_storage, new_storage)
Gitlab::GitalyClient.filesystem_id(old_storage) == Gitlab::GitalyClient.filesystem_id(new_storage)
end
end
---
title: Add write_registry scope to deploy tokens for container registry push access
merge_request: 28958
author:
type: added
# frozen_string_literal: true
class AddWriteRegistryToDeployTokens < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:deploy_tokens, :write_registry, :boolean, default: false, allow_null: false)
end
def down
remove_column(:deploy_tokens, :write_registry)
end
end
......@@ -1997,7 +1997,8 @@ CREATE TABLE public.deploy_tokens (
token character varying,
username character varying,
token_encrypted character varying(255),
deploy_token_type smallint DEFAULT 2 NOT NULL
deploy_token_type smallint DEFAULT 2 NOT NULL,
write_registry boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE public.deploy_tokens_id_seq
......@@ -13087,6 +13088,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200403185127
20200403185422
20200406135648
20200406192059
20200407094005
20200407094923
20200408110856
......
......@@ -26,6 +26,14 @@ watch [this 1 hour Q&A](https://www.youtube.com/watch?v=uCU8jdYzpac)
with [John Northrup](https://gitlab.com/northrup), and live questions coming
in from some of our customers.
GitLab offers a number of options to manage availability and resiliency. Below are the options to consider with trade-offs.
| Event | GitLab Feature | Recovery Point Objective (RPO) | Recovery Time Objective (RTO) | Cost |
| ----- | -------------- | --- | --- | ---- |
| Availability Zone failure | "GitLab HA" | No loss | No loss | 2x Git storage, multiple nodes balanced across AZ's |
| Region failure | "GitLab Disaster Recovery" | 5-10 minutes | 30 minutes | 2x primary cost |
| All failures | Backup/Restore | Last backup | Hours to Days | Cost of storing the backups |
## High availability
### Omnibus installation with automatic database failover
......
......@@ -92,7 +92,7 @@ POST /projects/:id/deploy_tokens
| `name` | string | yes | New deploy token's name |
| `expires_at` | datetime | no | Expiration date for the deploy token. Does not expire if no value is provided. |
| `username` | string | no | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
| `scopes` | array of strings | yes | Indicates the deploy token scopes. Must be at least one of `read_repository` or `read_registry`. |
| `scopes` | array of strings | yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, or `write_registry`. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"name": "My deploy token", "expires_at": "2021-01-01", "username": "custom-user", "scopes": ["read_repository"]}' "https://gitlab.example.com/api/v4/projects/5/deploy_tokens/"
......@@ -193,7 +193,7 @@ POST /groups/:id/deploy_tokens
| `name` | string | yes | New deploy token's name |
| `expires_at` | datetime | no | Expiration date for the deploy token. Does not expire if no value is provided. |
| `username` | string | no | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
| `scopes` | array of strings | yes | Indicates the deploy token scopes. Must be at least one of `read_repository` or `read_registry`. |
| `scopes` | array of strings | yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, or `write_registry`. |
Example request:
......
......@@ -75,6 +75,10 @@ count as active users in the subscription period in which they were originally a
- Members with Guest permissions on an Ultimate subscription.
- GitLab-created service accounts: `Ghost User` and `Support Bot`.
##### User Statistics
A breakdown of the users within your instance including active, billable and blocked can be found by navigating to **Admin Area > Overview > Dashboard** and selecting `Users Statistics` button within the `Users` widget..
NOTE: **Note:**
If you have LDAP integration enabled, anyone in the configured domain can sign up for a GitLab account. This can result in an unexpected bill at time of renewal. Consider [disabling new signups](../user/admin_area/settings/sign_up_restrictions.md) and managing new users manually instead.
......
......@@ -463,10 +463,41 @@ The DAST job does not require the project's repository to be present when runnin
## Running DAST in an offline environment
DAST can be executed on an offline GitLab Ultimate installation by using the following process:
For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
to external resources through the internet, some adjustments are required for the DAST job to
successfully run. For more information, see [Offline environments](../offline_deployments/index.md).
### Requirements for offline DAST support
To use DAST in an offline environment, you need:
- GitLab Runner with the [`docker` or `kubernetes` executor](#requirements).
- Docker Container Registry with a locally available copy of the DAST [container image](https://gitlab.com/gitlab-org/security-products/dast), found in the [DAST container registry](https://gitlab.com/gitlab-org/security-products/dast/container_registry).
NOTE: **Note:**
GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
meaning the runner may try to pull remote images even if a local copy is available. Set GitLab
Runner's [`pull_policy` to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
in an offline environment if you prefer using only locally available Docker images.
### Make GitLab DAST analyzer images available inside your Docker registry
For DAST, import the following default DAST analyzer image from `registry.gitlab.com` to your local "offline"
registry:
- `registry.gitlab.com/gitlab-org/security-products/dast:latest`
The process for importing Docker images into a local offline Docker registry depends on
**your network security policy**. Please consult your IT staff to find an accepted and approved
process by which external resources can be imported or temporarily accessed. Note that these scanners are [updated periodically](../index.md#maintenance-and-update-of-the-vulnerabilities-database)
with new definitions, so consider if you are able to make periodic updates yourself.
For details on saving and transporting Docker images as a file, see Docker's documentation on
[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
### Set DAST CI job variables to use local DAST analyzers
1. Host the DAST image `registry.gitlab.com/gitlab-org/security-products/dast:latest` in your local
Docker container registry.
1. Add the following configuration to your `.gitlab-ci.yml` file. You must replace `image` to refer
to the DAST Docker image hosted on your local Docker container registry:
......
......@@ -2,8 +2,9 @@
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17894) in GitLab 10.7.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/issues/199370) from **Settings > Repository** in GitLab 12.9.
> - [Added `write_registry` scope](https://gitlab.com/gitlab-org/gitlab/-/issues/22743) in GitLab 12.10.
Deploy tokens allow you to download (`git clone`) or read the container registry images of a project without having a user and a password.
Deploy tokens allow you to download (`git clone`) or push and pull the container registry images of a project without having a user and a password.
Deploy tokens can be managed by [maintainers only](../../permissions.md).
......@@ -44,6 +45,7 @@ the following table.
| ----- | ----------- |
| `read_repository` | Allows read-access to the repository through `git clone` |
| `read_registry` | Allows read-access to [container registry](../../packages/container_registry/index.md) images if a project is private and authorization is required. |
| `write_registry` | Allows write-access (push) to [container registry](../../packages/container_registry/index.md). |
## Deploy token custom username
......@@ -83,6 +85,21 @@ docker login -u <username> -p <deploy_token> registry.example.com
Just replace `<username>` and `<deploy_token>` with the proper values. Then you can simply
pull images from your Container Registry.
### Push Container Registry images
To push the container registry images, you'll need to:
1. Create a Deploy Token with `write_registry` as a scope.
1. Take note of your `username` and `token`.
1. Log in to GitLab’s Container Registry using the deploy token:
```shell
docker login -u <username> -p <deploy_token> registry.example.com
```
Just replace `<username>` and `<deploy_token>` with the proper values. Then you can simply
push images to your Container Registry.
### Group Deploy Token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/21765) in GitLab 12.9.
......@@ -107,7 +124,7 @@ There's a special case when it comes to Deploy Tokens. If a user creates one
named `gitlab-deploy-token`, the username and token of the Deploy Token will be
automatically exposed to the CI/CD jobs as environment variables: `CI_DEPLOY_USER` and
`CI_DEPLOY_PASSWORD`, respectively. With the GitLab Deploy Token, the
`read_registry` scope is implied.
`read_registry` and `write_registry` scopes are implied.
After you create the token, you can login to the Container Registry using
those variables:
......
......@@ -10,6 +10,7 @@ module API
result_hash = {}
result_hash[:read_registry] = scopes.include?('read_registry')
result_hash[:write_registry] = scopes.include?('write_registry')
result_hash[:read_repository] = scopes.include?('read_repository')
result_hash
end
......@@ -54,7 +55,7 @@ module API
params do
requires :name, type: String, desc: "New deploy token's name"
requires :scopes, type: Array[String], values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository" or "read_registry".'
desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", or "write_registry".'
optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
......@@ -117,7 +118,7 @@ module API
params do
requires :name, type: String, desc: 'The name of the deploy token'
requires :scopes, type: Array[String], values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository" or "read_registry".'
desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", or "write_registry".'
optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
......
......@@ -12,7 +12,7 @@ module Gitlab
REPOSITORY_SCOPES = [:read_repository, :write_repository].freeze
# Scopes used for GitLab Docker Registry access
REGISTRY_SCOPES = [:read_registry].freeze
REGISTRY_SCOPES = [:read_registry, :write_registry].freeze
# Scopes used for GitLab as admin
ADMIN_SCOPES = [:sudo].freeze
......@@ -200,6 +200,7 @@ module Gitlab
api: full_authentication_abilities,
read_api: read_only_authentication_abilities,
read_registry: [:read_container_image],
write_registry: [:create_container_image],
read_repository: [:download_code],
write_repository: [:download_code, :push_code]
}
......
......@@ -6835,6 +6835,9 @@ msgstr ""
msgid "DeployTokens|Allows read-only access to the repository"
msgstr ""
msgid "DeployTokens|Allows write access to the registry images"
msgstr ""
msgid "DeployTokens|Copy deploy token"
msgstr ""
......@@ -6853,7 +6856,7 @@ msgstr ""
msgid "DeployTokens|Deploy Tokens"
msgstr ""
msgid "DeployTokens|Deploy tokens allow read-only access to your repository and registry images."
msgid "DeployTokens|Deploy tokens allow access to your repository and registry images."
msgstr ""
msgid "DeployTokens|Expires"
......
......@@ -7,6 +7,7 @@ FactoryBot.define do
sequence(:name) { |n| "PDT #{n}" }
read_repository { true }
read_registry { true }
write_registry { false }
revoked { false }
expires_at { 5.days.from_now }
deploy_token_type { DeployToken.deploy_token_types[:project_type] }
......
......@@ -30,7 +30,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it 'optional_scopes contains all non-default scopes' do
stub_container_registry_config(enabled: true)
expect(subject.optional_scopes).to eq %i[read_user read_api read_repository write_repository read_registry sudo openid profile email]
expect(subject.optional_scopes).to eq %i[read_user read_api read_repository write_repository read_registry write_registry sudo openid profile email]
end
end
......@@ -38,21 +38,21 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it 'contains all non-default scopes' do
stub_container_registry_config(enabled: true)
expect(subject.all_available_scopes).to eq %i[api read_user read_api read_repository write_repository read_registry sudo]
expect(subject.all_available_scopes).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry sudo]
end
it 'contains for non-admin user all non-default scopes without ADMIN access' do
stub_container_registry_config(enabled: true)
user = create(:user, admin: false)
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry]
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry]
end
it 'contains for admin user all non-default scopes with ADMIN access' do
stub_container_registry_config(enabled: true)
user = create(:user, admin: true)
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry sudo]
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry sudo]
end
context 'registry_scopes' do
......@@ -72,7 +72,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end
it 'contains all registry related scopes' do
expect(subject.registry_scopes).to eq %i[read_registry]
expect(subject.registry_scopes).to eq %i[read_registry write_registry]
end
end
end
......@@ -401,6 +401,49 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context 'while using deploy tokens' do
let(:auth_failure) { Gitlab::Auth::Result.new(nil, nil) }
shared_examples 'registry token scope' do
it 'fails when login is not valid' do
expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
.to eq(auth_failure)
end
it 'fails when token is not valid' do
expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
.to eq(auth_failure)
end
it 'fails if token is nil' do
expect(gl_auth.find_for_git_client(login, nil, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
it 'fails if token is not related to project' do
expect(gl_auth.find_for_git_client(login, 'abcdef', project: nil, ip: 'ip'))
.to eq(auth_failure)
end
it 'fails if token has been revoked' do
deploy_token.revoke!
expect(deploy_token.revoked?).to be_truthy
expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
end
shared_examples 'deploy token with disabled registry' do
context 'when registry disabled' do
before do
stub_container_registry_config(enabled: false)
end
it 'fails when login and token are valid' do
expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
end
end
context 'when deploy token and user have the same username' do
let(:username) { 'normal_user' }
let(:user) { create(:user, username: username, password: 'my-secret') }
......@@ -425,34 +468,33 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context 'and belong to the same project' do
let!(:read_registry) { create(:deploy_token, username: 'deployer', read_repository: false, projects: [project]) }
let!(:read_repository) { create(:deploy_token, username: read_registry.username, read_registry: false, projects: [project]) }
let(:auth_success) { Gitlab::Auth::Result.new(read_repository, project, :deploy_token, [:download_code]) }
it 'succeeds for the right token' do
auth_success = Gitlab::Auth::Result.new(read_repository, project, :deploy_token, [:download_code])
expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: project, ip: 'ip'))
.to eq(auth_success)
end
it 'fails for the wrong token' do
expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: project, ip: 'ip'))
.to eq(auth_failure)
.not_to eq(auth_success)
end
end
context 'and belong to different projects' do
let_it_be(:other_project) { create(:project) }
let!(:read_registry) { create(:deploy_token, username: 'deployer', read_repository: false, projects: [project]) }
let!(:read_repository) { create(:deploy_token, username: read_registry.username, read_registry: false, projects: [project]) }
let!(:read_repository) { create(:deploy_token, username: read_registry.username, read_registry: false, projects: [other_project]) }
let(:auth_success) { Gitlab::Auth::Result.new(read_repository, other_project, :deploy_token, [:download_code]) }
it 'succeeds for the right token' do
auth_success = Gitlab::Auth::Result.new(read_repository, project, :deploy_token, [:download_code])
expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: project, ip: 'ip'))
expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: other_project, ip: 'ip'))
.to eq(auth_success)
end
it 'fails for the wrong token' do
expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: project, ip: 'ip'))
.to eq(auth_failure)
expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: other_project, ip: 'ip'))
.not_to eq(auth_success)
end
end
end
......@@ -542,45 +584,32 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
.to eq(auth_success)
end
it 'fails when login is not valid' do
expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
.to eq(auth_failure)
end
it_behaves_like 'registry token scope'
end
it 'fails when token is not valid' do
expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
.to eq(auth_failure)
end
it_behaves_like 'deploy token with disabled registry'
end
it 'fails if token is nil' do
expect(gl_auth.find_for_git_client(login, nil, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
context 'when the deploy token has write_registry as a scope' do
let_it_be(:deploy_token) { create(:deploy_token, write_registry: true, read_repository: false, read_registry: false, projects: [project]) }
let_it_be(:login) { deploy_token.username }
it 'fails if token is not related to project' do
expect(gl_auth.find_for_git_client(login, 'abcdef', project: nil, ip: 'ip'))
.to eq(auth_failure)
context 'when registry enabled' do
before do
stub_container_registry_config(enabled: true)
end
it 'fails if token has been revoked' do
deploy_token.revoke!
expect(deploy_token.revoked?).to be_truthy
expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
end
it 'succeeds when login and a project token are valid' do
auth_success = Gitlab::Auth::Result.new(deploy_token, project, :deploy_token, [:create_container_image])
context 'when registry disabled' do
before do
stub_container_registry_config(enabled: false)
expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
.to eq(auth_success)
end
it 'fails when login and token are valid' do
expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, ip: 'ip'))
.to eq(auth_failure)
end
it_behaves_like 'registry token scope'
end
it_behaves_like 'deploy token with disabled registry'
end
end
end
......
......@@ -62,7 +62,7 @@ describe DeployToken do
context 'with no scopes' do
it 'is invalid' do
deploy_token = build(:deploy_token, read_repository: false, read_registry: false)
deploy_token = build(:deploy_token, read_repository: false, read_registry: false, write_registry: false)
expect(deploy_token).not_to be_valid
expect(deploy_token.errors[:base].first).to eq("Scopes can't be blank")
......@@ -79,7 +79,7 @@ describe DeployToken do
context 'with only one scope' do
it 'returns scopes assigned to DeployToken' do
deploy_token = create(:deploy_token, read_registry: false)
deploy_token = create(:deploy_token, read_registry: false, write_registry: false)
expect(deploy_token.scopes).to eq([:read_repository])
end
end
......
......@@ -766,8 +766,8 @@ describe Auth::ContainerRegistryAuthenticationService do
{ scopes: ["repository:#{project.full_path}:pull"] }
end
context 'when deploy token has read_registry as a scope' do
let(:current_user) { create(:deploy_token, projects: [project]) }
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
......@@ -790,7 +790,7 @@ describe Auth::ContainerRegistryAuthenticationService do
{ scopes: ["repository:#{project.full_path}:push"] }
end
it_behaves_like 'an inaccessible'
it_behaves_like 'a pushable'
end
it_behaves_like 'able to login'
......@@ -808,7 +808,7 @@ describe Auth::ContainerRegistryAuthenticationService do
{ scopes: ["repository:#{project.full_path}:push"] }
end
it_behaves_like 'an inaccessible'
it_behaves_like 'a pushable'
end
it_behaves_like 'able to login'
......@@ -826,7 +826,7 @@ describe Auth::ContainerRegistryAuthenticationService do
{ scopes: ["repository:#{project.full_path}:push"] }
end
it_behaves_like 'an inaccessible'
it_behaves_like 'a pushable'
end
it_behaves_like 'able to login'
......
......@@ -311,6 +311,8 @@ describe Projects::ForkService do
fork_before_move = fork_project(project)
# Stub everything required to move a project to a Gitaly shard that does not exist
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
stub_storage_settings('test_second_storage' => { 'path' => TestEnv::SECOND_STORAGE_PATH })
allow_any_instance_of(Gitlab::Git::Repository).to receive(:create_repository)
.and_return(true)
......
......@@ -20,6 +20,8 @@ describe Projects::UpdateRepositoryStorageService do
let(:project_repository_double) { double(:repository) }
before do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
allow(Gitlab::Git::Repository).to receive(:new).and_call_original
allow(Gitlab::Git::Repository).to receive(:new)
.with('test_second_storage', project.repository.raw.relative_path, project.repository.gl_repository, project.repository.full_path)
......@@ -49,17 +51,20 @@ describe Projects::UpdateRepositoryStorageService do
end
end
context 'when the project is already on the target storage' do
context 'when the filesystems are the same' do
it 'bails out and does nothing' do
result = subject.execute(project.repository_storage)
expect(result[:status]).to eq(:error)
expect(result[:message]).to match(/repository and source have the same storage/)
expect(result[:message]).to match(/SameFilesystemError/)
end
end
context 'when the move fails' do
it 'unmarks the repository as read-only without updating the repository storage' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
expect(project_repository_double).to receive(:create_repository)
.and_return(true)
expect(project_repository_double).to receive(:replicate)
......@@ -77,6 +82,9 @@ describe Projects::UpdateRepositoryStorageService do
context 'when the checksum does not match' do
it 'unmarks the repository as read-only without updating the repository storage' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
expect(project_repository_double).to receive(:create_repository)
.and_return(true)
expect(project_repository_double).to receive(:replicate)
......@@ -97,6 +105,9 @@ describe Projects::UpdateRepositoryStorageService do
let!(:pool) { create(:pool_repository, :ready, source_project: project) }
it 'leaves the pool' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
expect(project_repository_double).to receive(:create_repository)
.and_return(true)
expect(project_repository_double).to receive(:replicate)
......
......@@ -46,7 +46,7 @@ RSpec.shared_examples 'a deploy token creation service' do
end
context 'when the deploy token is invalid' do
let(:deploy_token_params) { attributes_for(:deploy_token, read_repository: false, read_registry: false) }
let(:deploy_token_params) { attributes_for(:deploy_token, read_repository: false, read_registry: false, write_registry: false) }
it 'does not create a new DeployToken' do
expect { subject }.not_to change { DeployToken.count }
......
......@@ -22,6 +22,9 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
context 'when the move succeeds', :clean_gitlab_redis_shared_state do
before do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
allow(project_repository_double).to receive(:create_repository)
.and_return(true)
allow(project_repository_double).to receive(:replicate)
......@@ -83,17 +86,19 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
end
end
context 'when the project is already on the target storage' do
context 'when the filesystems are the same' do
it 'bails out and does nothing' do
result = subject.execute(project.repository_storage)
expect(result[:status]).to eq(:error)
expect(result[:message]).to match(/repository and source have the same storage/)
expect(result[:message]).to match(/SameFilesystemError/)
end
end
context "when the move of the #{repository_type} repository fails" do
it 'unmarks the repository as read-only without updating the repository storage' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
allow(project_repository_double).to receive(:create_repository)
.and_return(true)
allow(project_repository_double).to receive(:replicate)
......@@ -119,6 +124,8 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
context "when the checksum of the #{repository_type} repository does not match" do
it 'unmarks the repository as read-only without updating the repository storage' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
allow(project_repository_double).to receive(:create_repository)
.and_return(true)
allow(project_repository_double).to receive(:replicate)
......
......@@ -9,33 +9,12 @@ describe ProjectUpdateRepositoryStorageWorker do
subject { described_class.new }
describe "#perform" do
context 'when source and target repositories are on different filesystems' do
before do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('new_storage').and_return(SecureRandom.uuid)
it "calls the update repository storage service" do
expect_next_instance_of(Projects::UpdateRepositoryStorageService) do |instance|
expect(instance).to receive(:execute).with('new_storage')
end
it "calls the update repository storage service" do
expect_next_instance_of(Projects::UpdateRepositoryStorageService) do |instance|
expect(instance).to receive(:execute).with('new_storage')
end
subject.perform(project.id, 'new_storage')
end
end
context 'when source and target repositories are on the same filesystems' do
let(:filesystem_id) { SecureRandom.uuid }
before do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).and_return(filesystem_id)
end
it 'raises an error' do
expect_any_instance_of(::Projects::UpdateRepositoryStorageService).not_to receive(:new)
expect { subject.perform(project.id, 'new_storage') }.to raise_error(ProjectUpdateRepositoryStorageWorker::SameFilesystemError)
end
subject.perform(project.id, 'new_storage')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment