From 031122eb54390b4ed792289237ecfb156ec69002 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 30 Mar 2017 13:31:33 +0200 Subject: [PATCH] Add container repository create service with specs --- app/models/container_repository.rb | 4 + .../create_repository_service.rb | 33 +++++++++ .../create_repository_service_spec.rb | 74 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 app/services/container_registry/create_repository_service.rb create mode 100644 spec/services/container_registry/create_repository_service_spec.rb diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 98acf49c939..33e2574d389 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -58,4 +58,8 @@ class ContainerRepository < ActiveRecord::Base client.delete_repository_tag(self.path, digest) end end + + def self.create_from_path(path) + self.create(project: path.repository_project, name: path.repository_name) + end end diff --git a/app/services/container_registry/create_repository_service.rb b/app/services/container_registry/create_repository_service.rb new file mode 100644 index 00000000000..84218702a4f --- /dev/null +++ b/app/services/container_registry/create_repository_service.rb @@ -0,0 +1,33 @@ +module ContainerRegistry + ## + # Service for creating a container repository. + # + # It is usually executed before registry authenticator returns + # a token for given request. + # + class CreateRepositoryService < BaseService + def execute(path) + @path = path + + return if path.has_repository? + + unless user_can_create? || legacy_trigger_can_create? + raise Gitlab::Access::AccessDeniedError + end + + ContainerRepository.create_from_path(path) + end + + private + + def user_can_create? + can?(@current_user, :create_container_image, @path.repository_project) + end + + ## TODO, remove it after removing legacy triggers. + # + def legacy_trigger_can_create? + @current_user.nil? && @project == @path.repository_project + end + end +end diff --git a/spec/services/container_registry/create_repository_service_spec.rb b/spec/services/container_registry/create_repository_service_spec.rb new file mode 100644 index 00000000000..dfd07c8cc02 --- /dev/null +++ b/spec/services/container_registry/create_repository_service_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe ContainerRegistry::CreateRepositoryService, '#execute' do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + + let(:path) do + ContainerRegistry::Path.new("#{project.full_path}/my/image") + end + + let(:service) { described_class.new(project, user) } + + before do + stub_container_registry_config(enabled: true) + end + + context 'when container repository already exists' do + before do + create(:container_repository, project: project, name: 'my/image') + end + + it 'does not create container repository again' do + expect { service.execute(path) } + .to raise_error(Gitlab::Access::AccessDeniedError) + .and change { ContainerRepository.count }.by(0) + end + end + + context 'when repository is created by an user' do + context 'when user has no ability to create a repository' do + it 'does not create a new container repository' do + expect { service.execute(path) } + .to raise_error(Gitlab::Access::AccessDeniedError) + .and change { ContainerRepository.count }.by(0) + end + end + + context 'when user has ability do create a repository' do + before do + project.add_developer(user) + end + + it 'creates a new container repository' do + expect { service.execute(path) } + .to change { project.container_repositories.count }.by(1) + end + end + end + + context 'when repository is created by a legacy pipeline trigger' do + let(:user) { nil } + + context 'when repository path matches authenticated project' do + it 'creates a new container repository' do + expect { service.execute(path) } + .to change { project.container_repositories.count }.by(1) + end + end + + context 'when repository path does not match authenticated project' do + let(:private_project) { create(:empty_project, :private) } + + let(:path) do + ContainerRegistry::Path.new("#{private_project.full_path}/my/image") + end + + it 'does not create a new container repository' do + expect { service.execute(path) } + .to raise_error(Gitlab::Access::AccessDeniedError) + .and change { ContainerRepository.count }.by(0) + end + end + end +end