summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/models/container_repository.rb4
-rw-r--r--app/services/container_registry/create_repository_service.rb33
-rw-r--r--spec/services/container_registry/create_repository_service_spec.rb74
3 files changed, 111 insertions, 0 deletions
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