Add latest changes from gitlab-org/security/gitlab@16-4-stable-ee

This commit is contained in:
GitLab Bot 2023-11-29 16:27:29 +00:00
parent 7bfb929743
commit 14923c259b
19 changed files with 407 additions and 137 deletions

View File

@ -29,7 +29,7 @@ class Projects::TagsController < Projects::ApplicationController
tag_names = @tags.map(&:name)
@tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names)
@releases = project.releases.where(tag: tag_names)
@releases = ReleasesFinder.new(project, current_user, tag: tag_names).execute
@tag_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, @repository, current_user, @tags).execute
rescue Gitlab::Git::CommandError => e

View File

@ -30,7 +30,7 @@ module Types
def self.define_field_resolver_method(ability)
unless respond_to?(ability)
define_method ability.to_sym do |*args|
Ability.allowed?(context[:current_user], ability, object, args.to_h)
Ability.allowed?(context[:current_user], ability, object, **args.to_h)
end
end
end

View File

@ -70,13 +70,13 @@ class Ability
end
end
def allowed?(user, ability, subject = :global, opts = {})
def allowed?(user, ability, subject = :global, **opts)
if subject.is_a?(Hash)
opts = subject
subject = :global
end
policy = policy_for(user, subject)
policy = policy_for(user, subject, **opts.slice(:cache))
before_check(policy, ability.to_sym, user, subject, opts)
@ -100,8 +100,14 @@ class Ability
# See Support::AbilityCheck and Support::PermissionsCheck.
end
def policy_for(user, subject = :global)
DeclarativePolicy.policy_for(user, subject, cache: ::Gitlab::SafeRequestStore.storage)
# We cache in the request store by default. This can lead to unexpected
# results if abilities are re-checked after objects are modified and the
# check depends on the modified attributes. In such cases, you should pass
# `cache: false` for the second check to ensure all rules get re-evaluated.
def policy_for(user, subject = :global, cache: true)
policy_cache = cache ? ::Gitlab::SafeRequestStore.storage : {}
DeclarativePolicy.policy_for(user, subject, cache: policy_cache)
end
# This method is something of a band-aid over the problem. The problem is

View File

@ -33,10 +33,11 @@ class PagesDomain < ApplicationRecord
validates :verification_code, presence: true, allow_blank: false
validate :validate_pages_domain
validate :validate_matching_key, if: ->(domain) { domain.certificate.present? || domain.key.present? }
validate :validate_intermediates, if: ->(domain) { domain.certificate.present? && domain.certificate_changed? }
validate :validate_custom_domain_count_per_project, on: :create
validate :max_certificate_key_length, if: ->(domain) { domain.key.present? }
validate :validate_matching_key, if: ->(domain) { domain.certificate.present? || domain.key.present? }
# validate_intermediates must run after key validations to skip expensive SSL validation when there is a key error
validate :validate_intermediates, if: ->(domain) { domain.certificate.present? && domain.certificate_changed? && errors[:key].blank? }
validate :validate_custom_domain_count_per_project, on: :create
attribute :auto_ssl_enabled, default: -> { ::Gitlab::LetsEncrypt.enabled? }
attribute :wildcard, default: false

View File

@ -1297,8 +1297,8 @@ class User < MainClusterwide::ApplicationRecord
several_namespaces? || admin
end
def can?(action, subject = :global)
Ability.allowed?(self, action, subject)
def can?(action, subject = :global, **opts)
Ability.allowed?(self, action, subject, **opts)
end
def confirm_deletion_with_password?

View File

@ -25,7 +25,7 @@ module Ci
rule { can?(:create_pipeline) }.enable :play_pipeline_schedule
rule { can?(:admin_pipeline) | (can?(:update_build) & owner_of_schedule) }.policy do
rule { can?(:admin_pipeline) | (owner_of_schedule & can?(:update_build)) }.policy do
enable :admin_pipeline_schedule
enable :read_pipeline_schedule_variables
end
@ -45,6 +45,7 @@ module Ci
rule { protected_ref }.policy do
prevent :play_pipeline_schedule
prevent :create_pipeline_schedule
prevent :update_pipeline_schedule
end
private

View File

@ -51,7 +51,10 @@ class IssuePolicy < IssuablePolicy
prevent :read_issue
end
rule { ~can?(:read_issue) }.prevent :create_note
rule { ~can?(:read_issue) }.policy do
prevent :create_note
prevent :award_emoji
end
rule { locked }.policy do
prevent :reopen_issue

View File

@ -23,7 +23,11 @@ module Ci
attr_reader :project, :user, :params, :schedule
def allowed_to_save?
user.can?(self.class::AUTHORIZE, schedule)
# Disable cache because the same ability may already have been checked
# for the same records with different attributes. For example, we do not
# want an unauthorized user to change an unprotected ref to a protected
# ref.
user.can?(self.class::AUTHORIZE, schedule, cache: false)
end
def forbidden_to_save

View File

@ -12,6 +12,12 @@ module Ci
@params = params
end
def execute
return forbidden_to_save unless allowed_to_save?
super
end
private
def authorize_message

View File

@ -167,7 +167,7 @@
"marked-bidi": "^1.0.3",
"mathjax": "3",
"mdurl": "^1.0.1",
"mermaid": "10.5.0",
"mermaid": "10.6.1",
"micromatch": "^4.0.5",
"minimatch": "^3.0.4",
"monaco-editor": "^0.30.1",

View File

@ -65,6 +65,10 @@ RSpec.describe Projects::PipelineSchedulesController, feature_category: :continu
create(:protected_branch, *branch_access_levels, name: ref_name, project: project)
end
after do
ProtectedBranches::CacheService.new(project).refresh
end
it { expect { go }.to try(maintainer_accessible, :maintainer).of(project) }
it { expect { go }.to try(developer_accessible, :developer).of(project) }
end

View File

@ -52,6 +52,18 @@ RSpec.describe Projects::TagsController do
expect(assigns(:releases)).not_to include(invalid_release)
end
context 'when releases are private' do
before do
project.project_feature.update!(releases_access_level: ProjectFeature::PRIVATE)
end
it 'does not contain release data' do
subject
expect(assigns(:releases)).to be_empty
end
end
context '@tag_pipeline_status' do
context 'when no pipelines exist' do
it 'is empty' do

View File

@ -155,7 +155,6 @@ RSpec.describe 'User adds pages domain', :js, feature_category: :pages do
click_button 'Save Changes'
expect(page).to have_content('Certificate must be a valid PEM certificate')
expect(page).to have_content('Certificate misses intermediates')
expect(page).to have_content("Key doesn't match the certificate")
end
end

View File

@ -3,9 +3,42 @@
require 'spec_helper'
RSpec.describe Ability do
context 'using a nil subject' do
it 'has no permissions' do
expect(described_class.policy_for(nil, nil)).to be_banned
describe '#policy_for' do
subject(:policy) { described_class.policy_for(user, subject, **options) }
let(:user) { User.new }
let(:subject) { :global }
let(:options) { {} }
context 'using a nil subject' do
let(:user) { nil }
let(:subject) { nil }
it 'has no permissions' do
expect(policy).to be_banned
end
end
context 'with request store', :request_store do
before do
::Gitlab::SafeRequestStore.write(:example, :value) # make request store different from {}
end
it 'caches in the request store' do
expect(DeclarativePolicy).to receive(:policy_for).with(user, subject, cache: ::Gitlab::SafeRequestStore.storage)
policy
end
context 'when cache: false' do
let(:options) { { cache: false } }
it 'uses a fresh cache each time' do
expect(DeclarativePolicy).to receive(:policy_for).with(user, subject, cache: {})
policy
end
end
end
end

View File

@ -165,7 +165,7 @@ RSpec.describe PagesDomain do
it "adds error to certificate" do
domain.valid?
expect(domain.errors.attribute_names).to contain_exactly(:key, :certificate)
expect(domain.errors.attribute_names).to contain_exactly(:key)
end
end
@ -206,10 +206,25 @@ RSpec.describe PagesDomain do
it 'validates the certificate key length' do
valid_domain = build(:pages_domain, :key_length_8192)
expect(valid_domain).to be_valid
end
invalid_domain = build(:pages_domain, :extra_long_key)
expect(invalid_domain).to be_invalid
expect(invalid_domain.errors[:key]).to include('Certificate Key is too long. (Max 8192 bytes)')
context 'when the key has more than 8192 bytes' do
let(:domain) do
build(:pages_domain, :extra_long_key)
end
it 'adds a human readable error' do
expect(domain).to be_invalid
expect(domain.errors[:key]).to include('Certificate Key is too long. (Max 8192 bytes)')
end
it 'does not run SSL key verification' do
allow(domain).to receive(:validate_intermediates)
domain.valid?
expect(domain).not_to have_received(:validate_intermediates)
end
end
end
end

View File

@ -6,6 +6,7 @@ RSpec.describe Ci::PipelineSchedulePolicy, :models, :clean_gitlab_redis_cache, f
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
let_it_be(:other_user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, :repository, create_tag: tag_ref_name) }
let_it_be_with_reload(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
let_it_be(:tag_ref_name) { "v1.0.0" }
@ -17,89 +18,180 @@ RSpec.describe Ci::PipelineSchedulePolicy, :models, :clean_gitlab_redis_cache, f
describe 'rules' do
describe 'rules for protected ref' do
context 'for branch' do
subject(:policy) { described_class.new(user, pipeline_schedule) }
%w[refs/heads/master master].each do |branch_ref|
context "with #{branch_ref}" do
let_it_be(:branch_ref_name) { "master" }
let_it_be(:branch_pipeline_schedule) do
let_it_be(:pipeline_schedule) do
create(:ci_pipeline_schedule, :nightly, project: project, ref: branch_ref)
end
where(:push_access_level, :merge_access_level, :project_role, :accessible) do
:no_one_can_push | :no_one_can_merge | :owner | :be_disallowed
:no_one_can_push | :no_one_can_merge | :maintainer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :developer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :reporter | :be_disallowed
:no_one_can_push | :no_one_can_merge | :guest | :be_disallowed
shared_examples_for 'allowed by those who can update the branch' do
where(:push_access_level, :merge_access_level, :project_role, :accessible) do
:no_one_can_push | :no_one_can_merge | :owner | :be_disallowed
:no_one_can_push | :no_one_can_merge | :maintainer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :developer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :reporter | :be_disallowed
:no_one_can_push | :no_one_can_merge | :guest | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :owner | :be_allowed
:maintainers_can_push | :no_one_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :no_one_can_merge | :developer | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :guest | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :owner | :be_allowed
:maintainers_can_push | :no_one_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :no_one_can_merge | :developer | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :guest | :be_disallowed
:developers_can_push | :no_one_can_merge | :owner | :be_allowed
:developers_can_push | :no_one_can_merge | :maintainer | :be_allowed
:developers_can_push | :no_one_can_merge | :developer | :be_allowed
:developers_can_push | :no_one_can_merge | :reporter | :be_disallowed
:developers_can_push | :no_one_can_merge | :guest | :be_disallowed
:developers_can_push | :no_one_can_merge | :owner | :be_allowed
:developers_can_push | :no_one_can_merge | :maintainer | :be_allowed
:developers_can_push | :no_one_can_merge | :developer | :be_allowed
:developers_can_push | :no_one_can_merge | :reporter | :be_disallowed
:developers_can_push | :no_one_can_merge | :guest | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :owner | :be_allowed
:no_one_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:no_one_can_push | :maintainers_can_merge | :developer | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :guest | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :owner | :be_allowed
:no_one_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:no_one_can_push | :maintainers_can_merge | :developer | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :guest | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :owner | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :developer | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :guest | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :owner | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :developer | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :guest | :be_disallowed
:developers_can_push | :maintainers_can_merge | :owner | :be_allowed
:developers_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:developers_can_push | :maintainers_can_merge | :developer | :be_allowed
:developers_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:developers_can_push | :maintainers_can_merge | :guest | :be_disallowed
:developers_can_push | :maintainers_can_merge | :owner | :be_allowed
:developers_can_push | :maintainers_can_merge | :maintainer | :be_allowed
:developers_can_push | :maintainers_can_merge | :developer | :be_allowed
:developers_can_push | :maintainers_can_merge | :reporter | :be_disallowed
:developers_can_push | :maintainers_can_merge | :guest | :be_disallowed
:no_one_can_push | :developers_can_merge | :owner | :be_allowed
:no_one_can_push | :developers_can_merge | :maintainer | :be_allowed
:no_one_can_push | :developers_can_merge | :developer | :be_allowed
:no_one_can_push | :developers_can_merge | :reporter | :be_disallowed
:no_one_can_push | :developers_can_merge | :guest | :be_disallowed
:no_one_can_push | :developers_can_merge | :owner | :be_allowed
:no_one_can_push | :developers_can_merge | :maintainer | :be_allowed
:no_one_can_push | :developers_can_merge | :developer | :be_allowed
:no_one_can_push | :developers_can_merge | :reporter | :be_disallowed
:no_one_can_push | :developers_can_merge | :guest | :be_disallowed
:maintainers_can_push | :developers_can_merge | :owner | :be_allowed
:maintainers_can_push | :developers_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :developers_can_merge | :developer | :be_allowed
:maintainers_can_push | :developers_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :developers_can_merge | :guest | :be_disallowed
:maintainers_can_push | :developers_can_merge | :owner | :be_allowed
:maintainers_can_push | :developers_can_merge | :maintainer | :be_allowed
:maintainers_can_push | :developers_can_merge | :developer | :be_allowed
:maintainers_can_push | :developers_can_merge | :reporter | :be_disallowed
:maintainers_can_push | :developers_can_merge | :guest | :be_disallowed
:developers_can_push | :developers_can_merge | :owner | :be_allowed
:developers_can_push | :developers_can_merge | :maintainer | :be_allowed
:developers_can_push | :developers_can_merge | :developer | :be_allowed
:developers_can_push | :developers_can_merge | :reporter | :be_disallowed
:developers_can_push | :developers_can_merge | :guest | :be_disallowed
end
with_them do
before do
create(:protected_branch, push_access_level, merge_access_level, name: branch_ref_name,
project: project)
project.add_role(user, project_role)
:developers_can_push | :developers_can_merge | :owner | :be_allowed
:developers_can_push | :developers_can_merge | :maintainer | :be_allowed
:developers_can_push | :developers_can_merge | :developer | :be_allowed
:developers_can_push | :developers_can_merge | :reporter | :be_disallowed
:developers_can_push | :developers_can_merge | :guest | :be_disallowed
end
context 'for create_pipeline_schedule' do
subject(:policy) { described_class.new(user, new_branch_pipeline_schedule) }
let(:new_branch_pipeline_schedule) { project.pipeline_schedules.new(ref: branch_ref) }
with_them do
before do
create(:protected_branch, push_access_level, merge_access_level, name: branch_ref_name,
project: project)
project.add_role(user, project_role)
end
it { expect(policy).to try(accessible, :create_pipeline_schedule) }
end
end
context 'for play_pipeline_schedule' do
subject(:policy) { described_class.new(user, branch_pipeline_schedule) }
shared_examples_for 'only allowed by schedule owners who can update the branch' do
where(:push_access_level, :merge_access_level, :schedule_owner, :project_role, :accessible) do
:no_one_can_push | :no_one_can_merge | :other_user | :owner | :be_disallowed
:no_one_can_push | :no_one_can_merge | :user | :owner | :be_disallowed
:no_one_can_push | :no_one_can_merge | :user | :maintainer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :user | :developer | :be_disallowed
:no_one_can_push | :no_one_can_merge | :user | :reporter | :be_disallowed
:no_one_can_push | :no_one_can_merge | :user | :guest | :be_disallowed
it { expect(policy).to try(accessible, :play_pipeline_schedule) }
:maintainers_can_push | :no_one_can_merge | :other_user | :owner | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :user | :owner | :be_allowed
:maintainers_can_push | :no_one_can_merge | :user | :maintainer | :be_allowed
:maintainers_can_push | :no_one_can_merge | :user | :developer | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :user | :reporter | :be_disallowed
:maintainers_can_push | :no_one_can_merge | :user | :guest | :be_disallowed
:developers_can_push | :no_one_can_merge | :other_user | :owner | :be_disallowed
:developers_can_push | :no_one_can_merge | :user | :owner | :be_allowed
:developers_can_push | :no_one_can_merge | :user | :maintainer | :be_allowed
:developers_can_push | :no_one_can_merge | :user | :developer | :be_allowed
:developers_can_push | :no_one_can_merge | :user | :reporter | :be_disallowed
:developers_can_push | :no_one_can_merge | :user | :guest | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :other_user | :owner | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :user | :owner | :be_allowed
:no_one_can_push | :maintainers_can_merge | :user | :maintainer | :be_allowed
:no_one_can_push | :maintainers_can_merge | :user | :developer | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :user | :reporter | :be_disallowed
:no_one_can_push | :maintainers_can_merge | :user | :guest | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :other_user | :owner | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :user | :owner | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :user | :maintainer | :be_allowed
:maintainers_can_push | :maintainers_can_merge | :user | :developer | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :user | :reporter | :be_disallowed
:maintainers_can_push | :maintainers_can_merge | :user | :guest | :be_disallowed
:developers_can_push | :maintainers_can_merge | :other_user | :owner | :be_disallowed
:developers_can_push | :maintainers_can_merge | :user | :owner | :be_allowed
:developers_can_push | :maintainers_can_merge | :user | :maintainer | :be_allowed
:developers_can_push | :maintainers_can_merge | :user | :developer | :be_allowed
:developers_can_push | :maintainers_can_merge | :user | :reporter | :be_disallowed
:developers_can_push | :maintainers_can_merge | :user | :guest | :be_disallowed
:no_one_can_push | :developers_can_merge | :other_user | :owner | :be_disallowed
:no_one_can_push | :developers_can_merge | :user | :owner | :be_allowed
:no_one_can_push | :developers_can_merge | :user | :maintainer | :be_allowed
:no_one_can_push | :developers_can_merge | :user | :developer | :be_allowed
:no_one_can_push | :developers_can_merge | :user | :reporter | :be_disallowed
:no_one_can_push | :developers_can_merge | :user | :guest | :be_disallowed
:maintainers_can_push | :developers_can_merge | :other_user | :owner | :be_disallowed
:maintainers_can_push | :developers_can_merge | :user | :owner | :be_allowed
:maintainers_can_push | :developers_can_merge | :user | :maintainer | :be_allowed
:maintainers_can_push | :developers_can_merge | :user | :developer | :be_allowed
:maintainers_can_push | :developers_can_merge | :user | :reporter | :be_disallowed
:maintainers_can_push | :developers_can_merge | :user | :guest | :be_disallowed
:developers_can_push | :developers_can_merge | :other_user | :owner | :be_disallowed
:developers_can_push | :developers_can_merge | :user | :owner | :be_allowed
:developers_can_push | :developers_can_merge | :user | :maintainer | :be_allowed
:developers_can_push | :developers_can_merge | :user | :developer | :be_allowed
:developers_can_push | :developers_can_merge | :user | :reporter | :be_disallowed
:developers_can_push | :developers_can_merge | :user | :guest | :be_disallowed
end
with_them do
before do
create(:protected_branch, push_access_level, merge_access_level, name: branch_ref_name,
project: project)
project.add_role(user, project_role)
project.add_role(other_user, project_role)
pipeline_schedule.owner = schedule_owner == :user ? user : other_user
end
it { expect(policy).to try(accessible, ability_name) }
end
end
describe 'create_pipeline_schedule' do
let(:ability_name) { :create_pipeline_schedule }
let(:pipeline_schedule) { project.pipeline_schedules.new(ref: branch_ref) }
it_behaves_like 'allowed by those who can update the branch'
end
describe 'play_pipeline_schedule' do
let(:ability_name) { :play_pipeline_schedule }
it_behaves_like 'allowed by those who can update the branch'
end
describe 'update_pipeline_schedule' do
let(:ability_name) { :update_pipeline_schedule }
it_behaves_like 'only allowed by schedule owners who can update the branch'
end
end
end
@ -108,49 +200,97 @@ RSpec.describe Ci::PipelineSchedulePolicy, :models, :clean_gitlab_redis_cache, f
context 'for tag' do
%w[refs/tags/v1.0.0 v1.0.0].each do |tag_ref|
context "with #{tag_ref}" do
let_it_be(:tag_pipeline_schedule) do
let_it_be(:pipeline_schedule) do
create(:ci_pipeline_schedule, :nightly, project: project, ref: tag_ref)
end
where(:access_level, :project_role, :accessible) do
:no_one_can_create | :owner | :be_disallowed
:no_one_can_create | :maintainer | :be_disallowed
:no_one_can_create | :developer | :be_disallowed
:no_one_can_create | :reporter | :be_disallowed
:no_one_can_create | :guest | :be_disallowed
subject(:policy) { described_class.new(user, pipeline_schedule) }
:maintainers_can_create | :owner | :be_allowed
:maintainers_can_create | :maintainer | :be_allowed
:maintainers_can_create | :developer | :be_disallowed
:maintainers_can_create | :reporter | :be_disallowed
:maintainers_can_create | :guest | :be_disallowed
shared_examples_for 'allowed by those who can update the tag' do
where(:access_level, :project_role, :accessible) do
:no_one_can_create | :owner | :be_disallowed
:no_one_can_create | :maintainer | :be_disallowed
:no_one_can_create | :developer | :be_disallowed
:no_one_can_create | :reporter | :be_disallowed
:no_one_can_create | :guest | :be_disallowed
:developers_can_create | :owner | :be_allowed
:developers_can_create | :maintainer | :be_allowed
:developers_can_create | :developer | :be_allowed
:developers_can_create | :reporter | :be_disallowed
:developers_can_create | :guest | :be_disallowed
:maintainers_can_create | :owner | :be_allowed
:maintainers_can_create | :maintainer | :be_allowed
:maintainers_can_create | :developer | :be_disallowed
:maintainers_can_create | :reporter | :be_disallowed
:maintainers_can_create | :guest | :be_disallowed
:developers_can_create | :owner | :be_allowed
:developers_can_create | :maintainer | :be_allowed
:developers_can_create | :developer | :be_allowed
:developers_can_create | :reporter | :be_disallowed
:developers_can_create | :guest | :be_disallowed
end
with_them do
before do
create(:protected_tag, access_level, name: tag_ref_name, project: project)
project.add_role(user, project_role)
end
it { expect(policy).to try(accessible, ability_name) }
end
end
with_them do
before do
create(:protected_tag, access_level, name: tag_ref_name, project: project)
project.add_role(user, project_role)
shared_examples_for 'only allowed by schedule owners who can update the tag' do
where(:access_level, :schedule_owner, :project_role, :accessible) do
:no_one_can_create | :other_user | :owner | :be_disallowed
:no_one_can_create | :user | :owner | :be_disallowed
:no_one_can_create | :user | :maintainer | :be_disallowed
:no_one_can_create | :user | :developer | :be_disallowed
:no_one_can_create | :user | :reporter | :be_disallowed
:no_one_can_create | :user | :guest | :be_disallowed
:maintainers_can_create | :other_user | :owner | :be_disallowed
:maintainers_can_create | :user | :owner | :be_allowed
:maintainers_can_create | :user | :maintainer | :be_allowed
:maintainers_can_create | :user | :developer | :be_disallowed
:maintainers_can_create | :user | :reporter | :be_disallowed
:maintainers_can_create | :user | :guest | :be_disallowed
:developers_can_create | :other_user | :owner | :be_disallowed
:developers_can_create | :user | :owner | :be_allowed
:developers_can_create | :user | :maintainer | :be_allowed
:developers_can_create | :user | :developer | :be_allowed
:developers_can_create | :user | :reporter | :be_disallowed
:developers_can_create | :user | :guest | :be_disallowed
end
context 'for create_pipeline_schedule' do
subject(:policy) { described_class.new(user, new_tag_pipeline_schedule) }
with_them do
before do
create(:protected_tag, access_level, name: tag_ref_name, project: project)
project.add_role(user, project_role)
project.add_role(other_user, project_role)
let(:new_tag_pipeline_schedule) { project.pipeline_schedules.new(ref: tag_ref) }
pipeline_schedule.owner = schedule_owner == :user ? user : other_user
end
it { expect(policy).to try(accessible, :create_pipeline_schedule) }
it { expect(policy).to try(accessible, ability_name) }
end
end
context 'for play_pipeline_schedule' do
subject(:policy) { described_class.new(user, tag_pipeline_schedule) }
describe 'create_pipeline_schedule' do
let(:ability_name) { :create_pipeline_schedule }
let(:pipeline_schedule) { project.pipeline_schedules.new(ref: tag_ref) }
it { expect(policy).to try(accessible, :play_pipeline_schedule) }
end
it_behaves_like 'allowed by those who can update the tag'
end
describe 'play_pipeline_schedule' do
let(:ability_name) { :play_pipeline_schedule }
it_behaves_like 'allowed by those who can update the tag'
end
describe 'update_pipeline_schedule' do
let(:ability_name) { :update_pipeline_schedule }
it_behaves_like 'only allowed by schedule owners who can update the tag'
end
end
end

View File

@ -142,50 +142,50 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow non-members to read confidential issues' do
expect(permissions(non_member, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation)
expect(permissions(non_member, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(non_member, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation, :award_emoji)
expect(permissions(non_member, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'does not allow guests to read confidential issues' do
expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation)
expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation, :award_emoji)
expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'allows reporters to read, update, and admin confidential issues' do
expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'allows reporters from group links to read, update, and admin confidential issues' do
expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'allows issue authors to read and update their confidential issues' do
expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation)
expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation, :award_emoji)
expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation)
expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation, :award_emoji)
expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality, :award_emoji)
end
it 'does not allow issue author to read or update confidential issue moved to an private project' do
confidential_issue.project = create(:project, :private)
expect(permissions(author, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(author, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'allows issue assignees to read and update their confidential issues' do
expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue)
expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :award_emoji)
expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality)
expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
it 'does not allow issue assignees to read or update confidential issue moved to an private project' do
confidential_issue.project = create(:project, :private)
expect(permissions(assignee, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation)
expect(permissions(assignee, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation, :award_emoji)
end
end
end

View File

@ -7,16 +7,16 @@ RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuo
let_it_be_with_reload(:project) { create(:project, :public, :repository) }
let_it_be_with_reload(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:project_owner) { create(:user) }
let_it_be(:pipeline_schedule_variable) do
create(:ci_pipeline_schedule_variable,
key: 'foo', value: 'foovalue', pipeline_schedule: pipeline_schedule)
end
subject(:service) { described_class.new(pipeline_schedule, user, params) }
before_all do
project.add_maintainer(user)
project.add_owner(project_owner)
project.add_reporter(reporter)
pipeline_schedule.reload
@ -54,8 +54,10 @@ RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuo
subject(:service) { described_class.new(pipeline_schedule, user, params) }
it 'updates database values with passed params' do
expect { service.execute }
.to change { pipeline_schedule.description }.from('pipeline schedule').to('updated_desc')
expect do
service.execute
pipeline_schedule.reload
end.to change { pipeline_schedule.description }.from('pipeline schedule').to('updated_desc')
.and change { pipeline_schedule.ref }.from('master').to('patch-x')
.and change { pipeline_schedule.active }.from(true).to(false)
.and change { pipeline_schedule.cron }.from('0 1 * * *').to('*/1 * * * *')
@ -63,6 +65,48 @@ RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuo
.and change { pipeline_schedule.variables.last.value }.from('foovalue').to('barvalue')
end
context 'when the new branch is protected', :request_store do
let(:maintainer_access) { :no_one_can_merge }
before do
create(:protected_branch, :no_one_can_push, maintainer_access, name: 'patch-x', project: project)
end
after do
ProtectedBranches::CacheService.new(project).refresh
end
context 'when called by someone other than the schedule owner who can update the ref' do
let(:maintainer_access) { :maintainers_can_merge }
subject(:service) { described_class.new(pipeline_schedule, project_owner, params) }
it 'does not update the schedule' do
expect do
service.execute
pipeline_schedule.reload
end.not_to change { pipeline_schedule.description }
end
end
context 'when called by the schedule owner' do
it 'does not update the schedule' do
expect do
service.execute
pipeline_schedule.reload
end.not_to change { pipeline_schedule.description }
end
context 'when the owner can update the ref' do
let(:maintainer_access) { :maintainers_can_merge }
it 'updates the schedule' do
expect { service.execute }.to change { pipeline_schedule.description }
end
end
end
end
context 'when creating a variable' do
let(:params) do
{
@ -126,6 +170,8 @@ RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuo
end
end
it_behaves_like 'pipeline schedules checking variables permission'
it_behaves_like 'pipeline schedules checking variables permission' do
subject(:service) { described_class.new(pipeline_schedule, user, params) }
end
end
end

View File

@ -9450,10 +9450,10 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
mermaid@10.5.0:
version "10.5.0"
resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.5.0.tgz#e90512a65b5c6e29bd86cd04ce45aa31da2be76d"
integrity sha512-9l0o1uUod78D3/FVYPGSsgV+Z0tSnzLBDiC9rVzvelPxuO80HbN1oDr9ofpPETQy9XpypPQa26fr09VzEPfvWA==
mermaid@10.6.1:
version "10.6.1"
resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.6.1.tgz#701f4160484137a417770ce757ce1887a98c00fc"
integrity sha512-Hky0/RpOw/1il9X8AvzOEChfJtVvmXm+y7JML5C//ePYMy0/9jCEmW1E1g86x9oDfW9+iVEdTV/i+M6KWRNs4A==
dependencies:
"@braintree/sanitize-url" "^6.0.1"
"@types/d3-scale" "^4.0.3"