Skip to content
Snippets Groups Projects
Commit d83a3dd9 authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Automatic merge of gitlab-org/gitlab master

parents f0118a70 12ea6ff0
No related branches found
No related tags found
No related merge requests found
Showing
with 543 additions and 89 deletions
<script>
import { GlSprintf, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { GlSprintf, GlSafeHtmlDirective as SafeHtml, GlAvatarLink, GlAvatar } from '@gitlab/ui';
import $ from 'jquery';
import { escape, isEmpty } from 'lodash';
import { mapGetters, mapActions } from 'vuex';
......@@ -11,7 +11,6 @@ import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
import { truncateSha } from '~/lib/utils/text_utility';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import { __, s__, sprintf } from '~/locale';
import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../event_hub';
import noteable from '../mixins/noteable';
import resolvable from '../mixins/resolvable';
......@@ -31,11 +30,12 @@ export default {
name: 'NoteableNote',
components: {
GlSprintf,
userAvatarLink,
noteHeader,
noteActions,
NoteBody,
TimelineEntryItem,
GlAvatarLink,
GlAvatar,
},
directives: {
SafeHtml,
......@@ -196,13 +196,11 @@ export default {
return fileResolvedFromAvailableSource || null;
},
avatarSize() {
// Use a different size if shown on a Merge Request Diff
if (this.line && !this.isOverviewTab) {
return 24;
}
return 40;
isMRDiffView() {
return this.line && !this.isOverviewTab;
},
authorAvatarAdaptiveSize() {
return { default: 24, md: 32 };
},
},
created() {
......@@ -428,19 +426,33 @@ export default {
</template>
</gl-sprintf>
</div>
<div class="timeline-icon">
<user-avatar-link
:link-href="author.path"
:img-src="author.avatar_url"
:img-alt="author.name"
:img-size="avatarSize"
lazy
>
<template #avatar-badge>
<slot name="avatar-badge"></slot>
</template>
</user-avatar-link>
<div v-if="isMRDiffView" class="gl-float-left gl-mt-n1 gl-mr-3">
<gl-avatar-link :href="author.path">
<gl-avatar
:src="author.avatar_url"
:entity-name="author.username"
:alt="author.name"
:size="24"
/>
<slot name="avatar-badge"></slot>
</gl-avatar-link>
</div>
<div v-else class="gl-float-left gl-pl-3 gl-mr-3 gl-md-pl-2 gl-md-pr-2">
<gl-avatar-link :href="author.path">
<gl-avatar
:src="author.avatar_url"
:entity-name="author.username"
:alt="author.name"
:size="authorAvatarAdaptiveSize"
/>
<slot name="avatar-badge"></slot>
</gl-avatar-link>
</div>
<div class="timeline-content">
<div class="note-header">
<note-header
......
......@@ -59,7 +59,13 @@ class ProjectPolicy < BasePolicy
desc "Container registry is disabled"
condition(:container_registry_disabled, scope: :subject) do
!access_allowed_to?(:container_registry)
if user.is_a?(DeployToken)
(!user.read_registry? && !user.write_registry?) ||
user.revoked? ||
!project.container_registry_enabled?
else
!access_allowed_to?(:container_registry)
end
end
desc "Container registry is enabled for everyone with access to the project"
......@@ -88,6 +94,16 @@ class ProjectPolicy < BasePolicy
user.is_a?(DeployKey) && user.can_push_to?(project)
end
desc "Deploy token with read_container_image scope"
condition(:read_container_image_deploy_token) do
user.is_a?(DeployToken) && user.has_access_to?(project) && user.read_registry?
end
desc "Deploy token with create_container_image scope"
condition(:create_container_image_deploy_token) do
user.is_a?(DeployToken) && user.has_access_to?(project) && user.write_registry?
end
desc "Deploy token with read_package_registry scope"
condition(:read_package_registry_deploy_token) do
user.is_a?(DeployToken) && user.has_access_to?(project) && user.read_package_registry
......@@ -698,6 +714,14 @@ class ProjectPolicy < BasePolicy
enable :push_code
end
rule { read_container_image_deploy_token }.policy do
enable :read_container_image
end
rule { create_container_image_deploy_token }.policy do
enable :create_container_image
end
rule { read_package_registry_deploy_token }.policy do
enable :read_package
enable :read_project
......
......@@ -215,15 +215,13 @@ def user_can_pull?(requested_project)
def deploy_token_can_pull?(requested_project)
has_authentication_ability?(:read_container_image) &&
deploy_token.present? &&
deploy_token.has_access_to?(requested_project) &&
deploy_token.read_registry?
can?(deploy_token, :read_container_image, requested_project)
end
def deploy_token_can_push?(requested_project)
has_authentication_ability?(:create_container_image) &&
deploy_token.present? &&
deploy_token.has_access_to?(requested_project) &&
deploy_token.write_registry?
can?(deploy_token, :create_container_image, requested_project)
end
##
......
- if Gitlab.config.packages.enabled
%section.settings.as-package.no-animate#js-package-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Package Registry')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
......
- expanded = local_assigns.fetch(:expanded)
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Variables')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
......
......@@ -14,7 +14,7 @@
%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Continuous Integration and Deployment')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
......@@ -29,7 +29,7 @@
- if Gitlab.config.registry.enabled
%section.settings.as-registry.no-animate#js-registry-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Container Registry')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
......@@ -41,7 +41,7 @@
- if Feature.enabled?(:runner_registration_control)
%section.settings.as-runner.no-animate#js-runner-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= s_('Runners|Runner registration')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? 'Collapse' : 'Expand'
......
---
name: container_registry_legacy_authentication_for_deploy_tokens
introduced_by_url: https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/2470
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365968
milestone: '15.1'
type: development
group: group::package
default_enabled: false
......@@ -9,11 +9,16 @@ class AddIndexesIssuesOnProjectIdAndClosedAt < Gitlab::Database::Migration[2.0]
def up
# Index to improve performance when sorting issues by closed_at desc
add_concurrent_index :issues, 'project_id, closed_at DESC NULLS LAST, state_id, id', name: NEW_INDEX_NAME_1
unless index_exists_by_name?(:issues, NEW_INDEX_NAME_1)
add_concurrent_index :issues, 'project_id, closed_at DESC NULLS LAST, state_id, id', name: NEW_INDEX_NAME_1
end
# Index to improve performance when sorting issues by closed_at asc
# This replaces the old index which didn't account for state_id and id
add_concurrent_index :issues, [:project_id, :closed_at, :state_id, :id], name: NEW_INDEX_NAME_2
unless index_exists_by_name?(:issues, NEW_INDEX_NAME_2)
add_concurrent_index :issues, [:project_id, :closed_at, :state_id, :id], name: NEW_INDEX_NAME_2
end
remove_concurrent_index_by_name :issues, OLD_INDEX_NAME
end
......
......@@ -938,7 +938,7 @@ Prerequisites:
[cloud native chart](https://docs.gitlab.com/charts/charts/registry/#garbage-collection).
- You must set the Registry to [read-only mode](#performing-garbage-collection-without-downtime).
Running garbage collection causes downtime for the Container Registry. When you run this command
on an instance in an environment where another instances is still writing to the Registry storage,
on an instance in an environment where another instance is still writing to the Registry storage,
referenced manifests are removed.
### Understanding the content-addressable layers
......
......@@ -152,6 +152,10 @@ module GroupPolicy
@subject.feature_available?(:security_orchestration_policies)
end
condition(:group_level_compliance_dashboard_enabled) do
@subject.feature_available?(:group_level_compliance_dashboard)
end
rule { public_group | logged_in_viewable }.policy do
enable :read_wiki
enable :download_wiki_code
......@@ -190,6 +194,10 @@ module GroupPolicy
enable :read_wiki
end
rule { group_level_compliance_dashboard_enabled & auditor }.policy do
enable :read_group_compliance_dashboard
end
rule { owner | admin }.policy do
enable :owner_access
end
......
......@@ -362,6 +362,7 @@ module ProjectPolicy
prevent :read_merge_request
prevent :read_milestone
prevent :read_container_image
prevent :create_container_image
end
rule { locked_approvers_rules }.policy do
......
......@@ -42,6 +42,58 @@ def extra_info
})
end
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
override :deploy_token_can_pull?
def deploy_token_can_pull?(requested_project)
return false unless has_authentication_ability?(:read_container_image) && deploy_token.present?
root_group = requested_project.group&.root_ancestor
if root_group && ::Feature.enabled?(:container_registry_legacy_authentication_for_deploy_tokens, root_group)
read_granted = deploy_token.has_access_to?(requested_project) && deploy_token.read_registry?
log_ip_restriction(requested_project) if read_granted && ip_restricted?(requested_project)
read_granted
else
super
end
end
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
override :deploy_token_can_push?
def deploy_token_can_push?(requested_project)
return false unless has_authentication_ability?(:create_container_image) && deploy_token.present?
root_group = requested_project.group&.root_ancestor
if root_group && ::Feature.enabled?(:container_registry_legacy_authentication_for_deploy_tokens, root_group)
push_granted = deploy_token.has_access_to?(requested_project) && deploy_token.write_registry?
log_ip_restriction(requested_project) if push_granted && ip_restricted?(requested_project)
push_granted
else
super
end
end
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
def ip_restricted?(requested_project)
!::Gitlab::IpRestriction::Enforcer.new(requested_project.group).allows_current_ip?
end
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
def log_ip_restriction(requested_project)
::Gitlab::AuthLogger.warn(
class: self.class.name,
message: 'IP restriction violation',
deploy_token_id: deploy_token.id,
project_id: requested_project&.id,
project_path: requested_project&.full_path,
ip: ::Gitlab::IpAddressState.current
)
end
def access_denied_in_maintenance_mode?
@access_denied_in_maintenance_mode
end
......
......@@ -2180,4 +2180,30 @@ def expect_private_group_permissions_as_if_non_member
end
end
end
describe 'group level compliance dashboard' do
context 'feature enabled' do
before do
stub_licensed_features(group_level_compliance_dashboard: true)
end
context 'auditor' do
let(:current_user) { auditor }
it { is_expected.to be_allowed(:read_group_compliance_dashboard) }
end
end
context 'feature disabled' do
before do
stub_licensed_features(group_level_compliance_dashboard: false)
end
context 'auditor' do
let(:current_user) { auditor }
it { is_expected.to be_disallowed(:read_group_compliance_dashboard) }
end
end
end
end
......@@ -478,6 +478,7 @@
it { is_expected.to be_allowed(:read_merge_request) }
it { is_expected.to be_allowed(:read_milestone) }
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
end
context 'address is outside the range' do
......@@ -488,6 +489,7 @@
it { is_expected.to be_disallowed(:read_merge_request) }
it { is_expected.to be_disallowed(:read_milestone) }
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
context 'with admin enabled', :enable_admin_mode do
it { is_expected.to be_allowed(:read_project) }
......@@ -495,6 +497,7 @@
it { is_expected.to be_allowed(:read_merge_request) }
it { is_expected.to be_allowed(:read_milestone) }
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
end
context 'with admin disabled' do
......@@ -503,6 +506,7 @@
it { is_expected.to be_disallowed(:read_merge_request) }
it { is_expected.to be_disallowed(:read_milestone) }
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
context 'with auditor' do
......@@ -513,6 +517,7 @@
it { is_expected.to be_allowed(:read_merge_request) }
it { is_expected.to be_allowed(:read_milestone) }
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
end
end
end
......
......@@ -3,33 +3,163 @@
require 'spec_helper'
RSpec.describe JwtController do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let(:actions) { ['pull'] }
let(:expected_actions) { actions }
let(:scope) { "repository:#{project.full_path}:#{expected_actions.join(',')}" }
let(:service_name) { 'container_registry' }
let(:headers) { { authorization: credentials(user.username, user.password) } }
let(:parameters) { { account: user.username, client_id: 'docker', offline_token: true, service: service_name, scope: scope } }
shared_examples 'successful JWT auth' do
it 'allows access' do
get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(:ok)
expect(token_response['access']).to be_present
expect(token_access['actions']).to eq expected_actions
expect(token_access['type']).to eq 'repository'
expect(token_access['name']).to eq project.full_path
end
end
shared_examples 'unsuccessful JWT auth' do
it 'denies access' do
get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(:ok)
expect(token_response['access']).to eq []
end
end
context 'with IP restriction' do
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:group_deploy_token) { create(:deploy_token, :group, groups: [group], read_registry: true, write_registry: true) }
let_it_be(:project_deploy_token) { create(:deploy_token, projects: [project], read_registry: true, write_registry: true) }
let(:actions) { %w[push pull] }
before do
project.add_developer(user)
stub_container_registry_config(enabled: true, key: 'spec/fixtures/x509_certificate_pk.key')
allow(Gitlab::IpAddressState).to receive(:current).and_return('192.168.0.2')
stub_licensed_features(group_ip_restriction: true)
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
stub_feature_flags(container_registry_legacy_authentication_for_deploy_tokens: false)
end
context 'group with restriction' do
using RSpec::Parameterized::TableSyntax
before do
create(:ip_restriction, group: group, range: range)
end
shared_examples 'successful JWT auth with token' do
let(:headers) { { authorization: credentials(token.username, token.token) } }
where(:read, :write, :expected_actions) do
true | false | %w[pull]
false | true | %w[push]
true | true | %w[push pull]
end
with_them do
before do
token.update!(read_registry: read, write_registry: write)
end
it_behaves_like 'successful JWT auth'
end
end
context 'address is within the range' do
let(:range) { '192.168.0.0/24' }
it_behaves_like 'successful JWT auth'
context 'with project deploy token' do
let(:token) { project_deploy_token }
it_behaves_like 'successful JWT auth with token'
end
context 'with group deploy token' do
let(:token) { group_deploy_token }
it_behaves_like 'successful JWT auth with token'
end
end
context 'address is outside the range' do
let(:range) { '10.0.0.0/8' }
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
shared_examples 'allowing access if the root group is in the feature flag' do
before do
stub_feature_flags(container_registry_legacy_authentication_for_deploy_tokens: group)
end
it_behaves_like 'successful JWT auth with token'
it 'logs the ip restriction' do
token.update!(read_registry: true, write_registry: true)
logger_parameters = {
class: ::Auth::ContainerRegistryAuthenticationService.name,
message: 'IP restriction violation',
deploy_token_id: token.id,
project_id: project.id,
project_path: project.full_path,
ip: '192.168.0.2'
}
expect(Gitlab::AuthLogger).to receive(:warn).at_least(:once).with(logger_parameters)
get '/jwt/auth', params: parameters, headers: headers
end
end
it_behaves_like 'unsuccessful JWT auth'
context 'with deploy token credentials' do
let(:headers) { { authorization: credentials(token.username, token.token) } }
context 'with project deploy token' do
let(:token) { project_deploy_token }
it_behaves_like 'unsuccessful JWT auth'
it_behaves_like 'allowing access if the root group is in the feature flag'
end
context 'with group deploy token' do
let(:token) { group_deploy_token }
it_behaves_like 'unsuccessful JWT auth'
it_behaves_like 'allowing access if the root group is in the feature flag'
end
end
end
end
end
context 'authenticating against container registry' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :private, group: group) }
let(:scope) { "repository:#{project.full_path}:pull" }
let(:service_name) { 'container_registry' }
let(:headers) { { authorization: credentials(user.username, user.password) } }
let(:parameters) { { account: user.username, client_id: 'docker', offline_token: true, service: service_name, scope: scope } }
let_it_be(:project) { create(:project, :private, group: group) }
before do
stub_container_registry_config(enabled: true, issuer: 'gitlab-issuer', key: 'spec/fixtures/x509_certificate_pk.key')
project.add_reporter(user)
stub_container_registry_config(enabled: true, issuer: 'gitlab-issuer', key: 'spec/fixtures/x509_certificate_pk.key')
end
context 'when Group SSO is enforced' do
let!(:saml_provider) { create(:saml_provider, enforced_sso: true, group: group) }
let!(:identity) { create(:group_saml_identity, saml_provider: saml_provider, user: user) }
it 'allows access' do
get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(:ok)
expect(token_response['access']).to be_present
expect(token_access['actions']).to eq ['pull']
expect(token_access['type']).to eq 'repository'
expect(token_access['name']).to eq project.full_path
end
it_behaves_like 'successful JWT auth'
end
end
......
......@@ -5,6 +5,83 @@
RSpec.describe Auth::ContainerRegistryAuthenticationService do
include AdminModeHelper
describe 'with deploy keys' do
include_context 'container registry auth service context'
let_it_be_with_reload(:group) { create(:group, :public) }
let_it_be(:current_user) { nil }
let_it_be(:project) { create(:project, group: group) }
let(:deploy_token) { create(:deploy_token, projects: [project], read_registry: true, write_registry: true) }
before do
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
stub_feature_flags(container_registry_legacy_authentication_for_deploy_tokens: false)
end
context 'with IP restriction' do
before do
allow(Gitlab::IpAddressState).to receive(:current).and_return('192.168.0.2')
stub_licensed_features(group_ip_restriction: true)
end
context 'group with restriction' do
before do
create(:ip_restriction, group: group, range: range)
end
context 'address is within the range' do
let(:range) { '192.168.0.0/24' }
it_behaves_like 'a container registry auth service'
end
context 'address is outside the range' do
let(:range) { '10.0.0.0/8' }
let(:current_params) do
{ scopes: ["repository:#{project.full_path}:push,pull"], deploy_token: deploy_token }
end
context 'when actor is a deploy token with read access' do
it_behaves_like 'an inaccessible'
it_behaves_like 'not a container repository factory'
it_behaves_like 'logs an auth warning', %w(push pull)
# TODO : to remove along with container_registry_legacy_authentication_for_deploy_tokens
context 'when the root group is in the feature flag' do
before do
stub_feature_flags(container_registry_legacy_authentication_for_deploy_tokens: group)
end
it_behaves_like 'an accessible' do
let(:actions) { %w[push pull] }
end
it_behaves_like 'container repository factory'
it 'logs the ip restriction' do
logger_parameters = {
class: described_class.name,
message: 'IP restriction violation',
deploy_token_id: deploy_token.id,
project_id: project.id,
project_path: project.full_path,
ip: '192.168.0.2'
}
expect(Gitlab::AuthLogger).to receive(:warn).at_least(:once).with(logger_parameters)
subject
end
it_behaves_like 'a container registry auth service'
end
end
end
end
end
end
context 'in maintenance mode' do
include_context 'container registry auth service context'
......
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { GlAvatar } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import DiffsModule from '~/diffs/store/modules';
import NoteActions from '~/notes/components/note_actions.vue';
import NoteBody from '~/notes/components/note_body.vue';
import NoteHeader from '~/notes/components/note_header.vue';
import issueNote from '~/notes/components/noteable_note.vue';
import NotesModule from '~/notes/stores/modules';
import { NOTEABLE_TYPE_MAPPING } from '~/notes/constants';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { noteableDataMock, notesDataMock, note } from '../mock_data';
Vue.use(Vuex);
......@@ -205,19 +200,21 @@ describe('issue_note', () => {
await nextTick();
expect(wrapper.findComponent(UserAvatarLink).props('imgSize')).toBe(24);
const avatar = wrapper.findComponent(GlAvatar);
const avatarProps = avatar.props();
expect(avatarProps.size).toBe(24);
});
});
it('should render user information', () => {
it('should render user avatar', () => {
const { author } = note;
const avatar = wrapper.findComponent(UserAvatarLink);
const avatar = wrapper.findComponent(GlAvatar);
const avatarProps = avatar.props();
expect(avatarProps.linkHref).toBe(author.path);
expect(avatarProps.imgSrc).toBe(author.avatar_url);
expect(avatarProps.imgAlt).toBe(author.name);
expect(avatarProps.imgSize).toBe(40);
expect(avatarProps.src).toBe(author.avatar_url);
expect(avatarProps.entityName).toBe(author.username);
expect(avatarProps.alt).toBe(author.name);
expect(avatarProps.size).toEqual({ default: 24, md: 32 });
});
it('should render note header content', () => {
......
......@@ -1098,25 +1098,117 @@ def set_access_level(access_level)
subject { described_class.new(deploy_token, project) }
context 'a deploy token with read_package_registry scope' do
let(:deploy_token) { create(:deploy_token, read_package_registry: true) }
context 'private project' do
let(:project) { private_project }
it { is_expected.to be_allowed(:read_package) }
it { is_expected.to be_allowed(:read_project) }
it { is_expected.to be_disallowed(:create_package) }
context 'a deploy token with read_registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: true, write_registry: false) }
it_behaves_like 'package access with repository disabled'
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
context 'with registry disabled' do
include_context 'registry disabled via project features'
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
end
context 'a deploy token with write_registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: true) }
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
context 'with registry disabled' do
include_context 'registry disabled via project features'
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
end
context 'a deploy token with no registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: false) }
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
context 'a deploy token with read_package_registry scope' do
let(:deploy_token) { create(:deploy_token, read_repository: false, read_registry: false, read_package_registry: true) }
it { is_expected.to be_allowed(:read_project) }
it { is_expected.to be_allowed(:read_package) }
it { is_expected.to be_disallowed(:create_package) }
it_behaves_like 'package access with repository disabled'
end
context 'a deploy token with write_package_registry scope' do
let(:deploy_token) { create(:deploy_token, read_repository: false, read_registry: false, write_package_registry: true) }
it { is_expected.to be_allowed(:create_package) }
it { is_expected.to be_allowed(:read_package) }
it { is_expected.to be_allowed(:read_project) }
it { is_expected.to be_disallowed(:destroy_package) }
it_behaves_like 'package access with repository disabled'
end
end
context 'a deploy token with write_package_registry scope' do
let(:deploy_token) { create(:deploy_token, write_package_registry: true) }
context 'public project' do
let(:project) { public_project }
context 'a deploy token with read_registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: true, write_registry: false) }
it { is_expected.to be_allowed(:create_package) }
it { is_expected.to be_allowed(:read_package) }
it { is_expected.to be_allowed(:read_project) }
it { is_expected.to be_disallowed(:destroy_package) }
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
it_behaves_like 'package access with repository disabled'
context 'with registry disabled' do
include_context 'registry disabled via project features'
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
context 'with registry private' do
include_context 'registry set to private via project features'
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
end
context 'a deploy token with write_registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: true) }
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
context 'with registry disabled' do
include_context 'registry disabled via project features'
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
context 'with registry private' do
include_context 'registry set to private via project features'
it { is_expected.to be_allowed(:read_container_image) }
it { is_expected.to be_allowed(:create_container_image) }
end
end
context 'a deploy token with no registry scope' do
let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: false) }
it { is_expected.to be_disallowed(:read_container_image) }
it { is_expected.to be_disallowed(:create_container_image) }
end
end
end
......
# frozen_string_literal: true
RSpec.shared_context 'repository disabled via project features' do
before do
project.project_feature.update_columns(
# Disable merge_requests and builds as well, since merge_requests and
# builds cannot have higher visibility than repository.
merge_requests_access_level: ProjectFeature::DISABLED,
builds_access_level: ProjectFeature::DISABLED,
repository_access_level: ProjectFeature::DISABLED)
end
end
RSpec.shared_context 'registry disabled via project features' do
before do
project.project_feature.update_columns(
container_registry_access_level: ProjectFeature::DISABLED
)
end
end
RSpec.shared_context 'registry set to private via project features' do
before do
project.project_feature.update_columns(
container_registry_access_level: ProjectFeature::PRIVATE
)
end
end
......@@ -345,16 +345,7 @@
end
RSpec.shared_examples 'package access with repository disabled' do
context 'when repository is disabled' do
before do
project.project_feature.update!(
# Disable merge_requests and builds as well, since merge_requests and
# builds cannot have higher visibility than repository.
merge_requests_access_level: ProjectFeature::DISABLED,
builds_access_level: ProjectFeature::DISABLED,
repository_access_level: ProjectFeature::DISABLED)
end
include_context 'repository disabled via project features'
it { is_expected.to be_allowed(:read_package) }
end
it { is_expected.to be_allowed(:read_package) }
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment