diff --git a/CHANGELOG.md b/CHANGELOG.md index a4bd6b7915c8967c01bf6e233a922351c558a8d4..ed8770192fdb468af6cd3ac8ca2a905ee2274309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 16.8.2 (2024-02-07) + +### Fixed (3 changes) + +- [Fix Redis 6.0 compatibility breakage with Sidekiq 7 gem](gitlab-org/security/gitlab@e61868ad98d2ae640b3deec2b148c01fb52dba77) +- [Defer ConnectionPool instrumentation setup](gitlab-org/security/gitlab@d31ee125cd7ec9023b7558bd7af44c0293637b94) +- [Fix invalid records with FK not valid](gitlab-org/security/gitlab@a8dece6c5d160a218d9622a3dab0f93a7b2ca181) + +### Security (4 changes) + +- [Fix CI component input Regexp](gitlab-org/security/gitlab@96b81737b2b9f1aa3c9d710bc00b80be8359f68f) ([merge request](gitlab-org/security/gitlab!3854)) +- [Make scan result policies block renaming branches](gitlab-org/security/gitlab@6b12a71efe9c82b696cf1dc68c5aa2bc72e5fea3) ([merge request](gitlab-org/security/gitlab!3837)) +- [Restrict group access token creation for custom roles](gitlab-org/security/gitlab@e1d38e70f1f5c9defbb0ca2fa4608e603dcd2858) ([merge request](gitlab-org/security/gitlab!3834)) +- [Limit vulnerabilitiesCountByDay date range to 1 year](gitlab-org/security/gitlab@5e5428919d4773731bed7f724bd650dbc7555d9e) ([merge request](gitlab-org/security/gitlab!3826)) + ## 16.8.1 (2024-01-24) ### Fixed (1 change) @@ -504,6 +519,18 @@ entry. - [Bump the finalize_after date of backfill migration](gitlab-org/gitlab@770ab7faa2048bfeb8bddd506e6f37fe18bb4d06) ([merge request](gitlab-org/gitlab!140109)) - [Remove code_suggestions_completion_api feature](gitlab-org/gitlab@988e2f57f9635ed9cc3896b15965b608fce54756) ([merge request](gitlab-org/gitlab!138174)) **GitLab Enterprise Edition** +## 16.7.5 (2024-02-07) + +### Fixed (1 change) + +- [Update dependency prometheus-client-mmap to '~> 1.1', '>= 1.1.1'](gitlab-org/security/gitlab@41326f12836b409735f0745d57b135fd952b54e0) + +### Security (3 changes) + +- [Fix CI component input Regexp](gitlab-org/security/gitlab@7b29c348a90b3311c5661b57572cbedf6160d02a) ([merge request](gitlab-org/security/gitlab!3855)) +- [Make scan result policies block renaming branches](gitlab-org/security/gitlab@5f8202c849059e28370d79aa79cd94a851abd61a) ([merge request](gitlab-org/security/gitlab!3838)) +- [Limit vulnerabilitiesCountByDay date range to 1 year](gitlab-org/security/gitlab@95c1de1c1c297ba59e7e52485e9703b01d8ad552) ([merge request](gitlab-org/security/gitlab!3827)) + ## 16.7.4 (2024-01-24) ### Fixed (1 change) @@ -1444,6 +1471,14 @@ entry. - [Move export buttons next to each other](gitlab-org/gitlab@106bea7a6246cd153cf66d133936a09d46369ae3) ([merge request](gitlab-org/gitlab!137461)) +## 16.6.7 (2024-02-07) + +### Security (3 changes) + +- [Fix CI component input Regexp](gitlab-org/security/gitlab@4aea3a2d7f371d57a00eef647f84dce2b6963dc6) ([merge request](gitlab-org/security/gitlab!3856)) +- [Make scan result policies block renaming branches](gitlab-org/security/gitlab@6ea7b750df3a5c2505717555db0875be6b0b3cd0) ([merge request](gitlab-org/security/gitlab!3840)) +- [Limit vulnerabilitiesCountByDay date range to 1 year](gitlab-org/security/gitlab@4896b80a35e3a31b2cf0df28a3545ba5caf9cc6f) ([merge request](gitlab-org/security/gitlab!3831)) + ## 16.6.6 (2024-01-24) ### Fixed (1 change) diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index 824b1a8c377ee7f0e5ea941125f68798aeb2a886..c36cc981341381e25f8396194ad9f895e7d0dc16 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -128,11 +128,10 @@ def success(access_token) end def validate_access_level(access_level) - return true unless resource.is_a?(Project) return true if current_user.bot? - return true if current_user.can?(:manage_owners, resource) + return true if current_user.can?(:owner_access, resource) - current_user.authorized_project?(resource, access_level.to_i) + resource.member?(current_user, access_level.to_i) end def do_not_allow_owner_access_level_for_project_bot?(access_level) diff --git a/app/views/groups/settings/access_tokens/index.html.haml b/app/views/groups/settings/access_tokens/index.html.haml index 832fd6e8cebbf85668878ddae459846777382418..b45c5dc7d5fdf14cd8ea6ee6f6883e736019836e 100644 --- a/app/views/groups/settings/access_tokens/index.html.haml +++ b/app/views/groups/settings/access_tokens/index.html.haml @@ -47,7 +47,7 @@ resource: @group, token: @resource_access_token, scopes: @scopes, - access_levels: GroupMember.access_level_roles, + access_levels: access_level_roles_user_can_assign(@group), default_access_level: Gitlab::Access::GUEST, prefix: :resource_access_token, description_prefix: :group_access_token, diff --git a/ee/app/graphql/resolvers/vulnerabilities_count_per_day_resolver.rb b/ee/app/graphql/resolvers/vulnerabilities_count_per_day_resolver.rb index 36269fff98ac0532b1b46d0b07fc4e2e99b99bdf..26a62e4ac31149b1ce91ad038e84c79344a85e0a 100644 --- a/ee/app/graphql/resolvers/vulnerabilities_count_per_day_resolver.rb +++ b/ee/app/graphql/resolvers/vulnerabilities_count_per_day_resolver.rb @@ -4,6 +4,8 @@ module Resolvers class VulnerabilitiesCountPerDayResolver < VulnerabilitiesBaseResolver include Gitlab::Graphql::Authorize::AuthorizeResource + MAX_DATE_RANGE_DAYS = 1.year.in_days.floor.freeze + type Types::VulnerabilitiesCountByDayType, null: true authorize :read_security_resource @@ -19,6 +21,8 @@ def resolve(**args) # Instance security dashboard does not have an object to authorize against. authorize!(object) unless resolve_vulnerabilities_for_instance_security_dashboard? + validate_date_range!(args) + return [] unless vulnerable vulnerable @@ -32,6 +36,14 @@ def resolve(**args) private + def validate_date_range!(args) + # GraphQL::Types::ISO8601Date is instantiated as Date and the difference between + # two dates is the number of days between them. + return unless (args[:end_date] - args[:start_date]) > MAX_DATE_RANGE_DAYS + + raise Gitlab::Graphql::Errors::ArgumentError, "maximum date range is #{MAX_DATE_RANGE_DAYS} days" + end + def generate_missing_dates(calendar_entries, start_date, end_date) severities = ::Enums::Vulnerability.severity_levels.keys (start_date..end_date) diff --git a/ee/app/models/security/scan_result_policy_read.rb b/ee/app/models/security/scan_result_policy_read.rb index 05bd107dbc890265aebc8c9af6e7ae75fba807c0..10ae9438801db28052b5998a42b87fa9c570a926 100644 --- a/ee/app/models/security/scan_result_policy_read.rb +++ b/ee/app/models/security/scan_result_policy_read.rb @@ -33,6 +33,9 @@ class ScanResultPolicyRead < ApplicationRecord scope :for_project, ->(project) { where(project: project) } scope :targeting_commits, -> { where.not(commits: nil) } scope :including_approval_merge_request_rules, -> { includes(:approval_merge_request_rules) } + scope :blocking_branch_modification, -> do + where("project_approval_settings->>'block_branch_modification' = 'true'") + end def newly_detected? license_states.include?(ApprovalProjectRule::NEWLY_DETECTED) diff --git a/ee/app/services/ee/protected_branches/renaming_blocked_by_policy.rb b/ee/app/services/ee/protected_branches/renaming_blocked_by_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..ad34fa7d1072542d34987c72959196c9fd85de5b --- /dev/null +++ b/ee/app/services/ee/protected_branches/renaming_blocked_by_policy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module EE + module ProtectedBranches + module RenamingBlockedByPolicy + def execute(protected_branch) + raise ::Gitlab::Access::AccessDeniedError if renaming? && blocked?(protected_branch) + + super + end + + private + + def renaming? + params.key?(:name) + end + + def blocked?(protected_branch) + return blocking_branch_modification?(protected_branch.project) if protected_branch.project_level? + + blocking_group_branch_modification?(protected_branch.group) + end + + def blocking_branch_modification?(project) + return false unless project&.licensed_feature_available?(:security_orchestration_policies) + return false unless ::Feature.enabled?(:scan_result_policies_block_unprotecting_branches, project) + + project.scan_result_policy_reads.blocking_branch_modification.exists? + end + + def blocking_group_branch_modification?(group) + return false unless group&.licensed_feature_available?(:security_orchestration_policies) + return false unless ::Feature.enabled?(:scan_result_policy_block_group_branch_modification, group) + + ::Security::SecurityOrchestrationPolicies::GroupProtectedBranchesDeletionCheckService + .new(group: group) + .execute + end + end + end +end diff --git a/ee/app/services/ee/protected_branches/update_service.rb b/ee/app/services/ee/protected_branches/update_service.rb index 86d5f8c5f63822d17ea0baad2a5237d30842a3cd..c79418d1f223c795331e61cd61ac0a6b5c191393 100644 --- a/ee/app/services/ee/protected_branches/update_service.rb +++ b/ee/app/services/ee/protected_branches/update_service.rb @@ -3,6 +3,8 @@ module EE module ProtectedBranches module UpdateService + prepend RenamingBlockedByPolicy + def after_execute(protected_branch:, old_merge_access_levels:, old_push_access_levels:) super diff --git a/ee/spec/controllers/ee/projects/protected_branches_controller_spec.rb b/ee/spec/controllers/ee/projects/protected_branches_controller_spec.rb index b72ad254c5fe83feab79fca2f7e3d39f949be16a..1372a9b262b5f356b7ab7f035b3a8efcb0fa3427 100644 --- a/ee/spec/controllers/ee/projects/protected_branches_controller_spec.rb +++ b/ee/spec/controllers/ee/projects/protected_branches_controller_spec.rb @@ -11,17 +11,17 @@ project.add_maintainer(user) end - shared_examples "protected branch with code owner approvals feature" do |boolean| - it "sets code owner approvals to #{boolean} when protecting the branch" do - expect do - post(:create, params: project_params.merge(protected_branch: create_params)) - end.to change { ProtectedBranch.count }.by(1) + describe "POST #create" do + shared_examples "protected branch with code owner approvals feature" do |boolean| + it "sets code owner approvals to #{boolean} when protecting the branch" do + expect do + post(:create, params: project_params.merge(protected_branch: create_params)) + end.to change { ProtectedBranch.count }.by(1) - expect(ProtectedBranch.last.attributes["code_owner_approval_required"]).to eq(boolean) + expect(ProtectedBranch.last.attributes["code_owner_approval_required"]).to eq(boolean) + end end - end - describe "POST #create" do let(:maintainer_access_level) { [{ access_level: Gitlab::Access::MAINTAINER }] } let(:access_level_params) do { merge_access_levels_attributes: maintainer_access_level, @@ -66,4 +66,67 @@ end end end + + describe "PUT/PATCH #update" do + let(:new_name) { "foobar" } + + let(:params) do + { namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: protected_branch.id, + protected_branch: { name: new_name } } + end + + subject(:update_protected_branch) { put(:update, params: params) } + + before do + sign_in(user) + end + + context 'without blocking scan result policy' do + it 'renames' do + expect { update_protected_branch }.to change { protected_branch.reload.name }.to(new_name) + end + end + + context 'with blocking scan result policy' do + let(:branch_name) { protected_branch.name } + let(:policy_configuration) do + create(:security_orchestration_policy_configuration, project: project) + end + + include_context 'with scan result policy blocking protected branches' + + before do + create(:scan_result_policy_read, :blocking_protected_branches, project: project, + security_orchestration_policy_configuration: policy_configuration) + end + + it 'does not rename' do + expect { update_protected_branch }.not_to change { protected_branch.reload.name } + end + + it 'responds with 403' do + update_protected_branch + + expect(response).to have_gitlab_http_status(:forbidden) + end + + context 'with feature disabled' do + before do + stub_feature_flags(scan_result_policies_block_unprotecting_branches: false) + end + + it 'renames' do + expect { update_protected_branch }.to change { protected_branch.reload.name }.to(new_name) + end + + it 'responds with 200' do + update_protected_branch + + expect(response).to have_gitlab_http_status(:success) + end + end + end + end end diff --git a/ee/spec/models/security/scan_result_policy_read_spec.rb b/ee/spec/models/security/scan_result_policy_read_spec.rb index e5c4b83ab65eddced1daeade87634fca12d0f8d6..ca021b0de52d3bd1e3ae4c1d54590e2163c9b011 100644 --- a/ee/spec/models/security/scan_result_policy_read_spec.rb +++ b/ee/spec/models/security/scan_result_policy_read_spec.rb @@ -63,6 +63,19 @@ it { is_expected.to define_enum_for(:age_interval).with_values(**age_interval_values) } end + describe 'scopes' do + describe '.blocking_branch_modification' do + let_it_be(:non_blocking_read) { create(:scan_result_policy_read) } + let_it_be(:blocking_read) do + create(:scan_result_policy_read, project_approval_settings: { block_branch_modification: true }) + end + + it 'returns blocking reads' do + expect(described_class.blocking_branch_modification).to contain_exactly(blocking_read) + end + end + end + describe '#newly_detected?' do subject { scan_result_policy_read.newly_detected? } diff --git a/ee/spec/requests/api/graphql/branch_rules/update_spec.rb b/ee/spec/requests/api/graphql/branch_rules/update_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..56e51bf24874e7a6062a179e59173fcfb9b32ecd --- /dev/null +++ b/ee/spec/requests/api/graphql/branch_rules/update_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'BranchRuleUpdate', feature_category: :source_code_management do + include GraphqlHelpers + + let_it_be(:project) { create(:project, :public) } + let_it_be(:user) { create(:user) } + let!(:branch_rule) { create(:protected_branch, project: project) } + let(:current_user) { user } + let(:mutation) { graphql_mutation(:branch_rule_update, params) } + + let(:params) do + { + id: branch_rule.to_global_id, + project_path: project.full_path, + name: branch_rule.name.reverse + } + end + + subject(:post_mutation) { post_graphql_mutation(mutation, current_user: user) } + + before_all do + project.add_maintainer(user) + end + + context 'with blocking scan result policy' do + let(:branch_name) { branch_rule.name } + let(:policy_configuration) do + create(:security_orchestration_policy_configuration, project: project) + end + + include_context 'with scan result policy blocking protected branches' + + before do + create(:scan_result_policy_read, :blocking_protected_branches, project: project, + security_orchestration_policy_configuration: policy_configuration) + end + + it_behaves_like 'a mutation that returns top-level errors', + errors: ["Internal server error: Gitlab::Access::AccessDeniedError"] + end +end diff --git a/ee/spec/requests/api/graphql/vulnerabilities/instance_vulnerability_count_by_day_spec.rb b/ee/spec/requests/api/graphql/vulnerabilities/instance_vulnerability_count_by_day_spec.rb index 4c306c8554a922036cfbda48eb098664cde92c9a..159aa9c38dd1b94c5985ce4981ed22d0892df20d 100644 --- a/ee/spec/requests/api/graphql/vulnerabilities/instance_vulnerability_count_by_day_spec.rb +++ b/ee/spec/requests/api/graphql/vulnerabilities/instance_vulnerability_count_by_day_spec.rb @@ -44,6 +44,16 @@ end end + context 'when requesting a large date range' do + let(:args) { { start_date: 366.days.before(date), end_date: date } } + + it 'returns an error' do + max_days = ::Resolvers::VulnerabilitiesCountPerDayResolver::MAX_DATE_RANGE_DAYS + + expect_graphql_errors_to_include("maximum date range is #{max_days} days") + end + end + context 'when user has permission to access the security dashboard of the project' do before_all do project.add_developer(current_user) diff --git a/ee/spec/requests/custom_roles/manage_group_access_tokens/request_spec.rb b/ee/spec/requests/custom_roles/manage_group_access_tokens/request_spec.rb index eb606a902c373e3010f7eec326b7133179c17646..8d2e04ae9770a7ee494526b7844e48e8464334e0 100644 --- a/ee/spec/requests/custom_roles/manage_group_access_tokens/request_spec.rb +++ b/ee/spec/requests/custom_roles/manage_group_access_tokens/request_spec.rb @@ -25,20 +25,39 @@ end describe '#create' do - let_it_be(:access_token_params) { { name: 'TestToken', scopes: ['api'], expires_at: Date.today + 1.month } } let_it_be(:resource) { group } + let(:access_token_params) do + { name: 'TestToken', scopes: ['api'], expires_at: Date.today + 1.month, access_level: access_level } + end subject(:request) do post group_settings_access_tokens_path(group, params: { resource_access_token: access_token_params }) end - it 'user has access via a custom role' do - request + context 'when creating a token with an access level that is lower or equal to the current users access level' do + let(:access_level) { 10 } - expect(response).to have_gitlab_http_status(:ok) + it 'user has access via a custom role' do + request + + expect(response).to have_gitlab_http_status(:ok) + end + + it_behaves_like 'POST resource access tokens available' end - it_behaves_like 'POST resource access tokens available' + context 'when creating a token with an access level that is higher than the current users access level' do + let(:access_level) { 20 } + + it 'renders JSON with an error' do + request + + expect(response.parsed_body['new_token']).to be_blank + expect(response.parsed_body['errors']) + .to include("Access level of the token can't be greater the access level of the user who created the token") + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end end describe '#revoke' do diff --git a/ee/spec/requests/groups/protected_branches_controller_spec.rb b/ee/spec/requests/groups/protected_branches_controller_spec.rb index c3f2f1de3590e8d6e58b11ead5ba3533ba89e51a..289c795e12b2518eea5496e00e4a60af4cedc4ae 100644 --- a/ee/spec/requests/groups/protected_branches_controller_spec.rb +++ b/ee/spec/requests/groups/protected_branches_controller_spec.rb @@ -144,6 +144,56 @@ expect(response).to have_gitlab_http_status(:unprocessable_entity) end end + + context 'with blocking scan result policy' do + shared_examples 'prevents update of protected branch' do + let(:branch_name) { protected_branch.name } + let(:policy_configuration) do + create(:security_orchestration_policy_configuration, :namespace, namespace_id: group.id) + end + + before do + stub_licensed_features(group_protected_branches: true, security_orchestration_policies: true) + end + + it 'does not rename' do + expect { patch member_path, params: update_params }.not_to change { protected_branch.reload.name } + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'responds with 403' do + patch member_path, params: update_params + + expect(response).to have_gitlab_http_status(:forbidden) + end + + context 'with feature disabled' do + before do + stub_feature_flags(scan_result_policy_block_group_branch_modification: false) + end + + it 'renames' do + expect { patch member_path, params: update_params }.to change { + protected_branch.reload.name + }.to(update_params.dig(:protected_branch, :name)) + end + + it 'responds with 200' do + patch member_path, params: update_params + + expect(response).to have_gitlab_http_status(:success) + end + end + end + + include_context 'with scan result policy blocking protected branches' do + include_examples 'prevents update of protected branch' + end + + include_context 'with scan result policy blocking group-level protected branches' do + include_examples 'prevents update of protected branch' + end + end end describe "DELETE #destroy" do diff --git a/ee/spec/services/ee/protected_branches/update_service_spec.rb b/ee/spec/services/ee/protected_branches/update_service_spec.rb index 85805d0bec624d7f4dc54dcb55cb212f8f2d34fb..2bdde47981f8cc6a5f4464498cbe1720450ed7d6 100644 --- a/ee/spec/services/ee/protected_branches/update_service_spec.rb +++ b/ee/spec/services/ee/protected_branches/update_service_spec.rb @@ -38,4 +38,81 @@ end end end + + describe 'blocking scan result policies' do + context 'with project-level protected branch' do + let(:params) { { name: branch_name.reverse } } + + let(:policy_configuration) do + create(:security_orchestration_policy_configuration, project: project) + end + + include_context 'with scan result policy blocking protected branches' + + before do + create(:scan_result_policy_read, :blocking_protected_branches, project: project, + security_orchestration_policy_configuration: policy_configuration) + end + + it 'raises' do + expect { service.execute(protected_branch) }.to raise_error(::Gitlab::Access::AccessDeniedError) + end + + context 'with feature disabled' do + before do + stub_feature_flags(scan_result_policies_block_unprotecting_branches: false) + end + + it 'renames' do + expect { service.execute(protected_branch) }.to change { + protected_branch.reload.name + }.to(branch_name.reverse) + end + end + end + + context 'with group-level protected branch' do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:protected_branch) { create(:protected_branch, project_id: nil, namespace_id: group.id) } + + before_all do + group.add_owner(user) + end + + context 'with blocking scan result policy' do + let(:params) { { name: branch_name.reverse } } + + let(:policy_configuration) do + create(:security_orchestration_policy_configuration, :namespace, namespace_id: group.id) + end + + shared_examples 'prevents update of protected branch' do + it 'raises' do + expect { service.execute(protected_branch) }.to raise_error(::Gitlab::Access::AccessDeniedError) + end + + context 'with feature disabled' do + before do + stub_feature_flags(scan_result_policy_block_group_branch_modification: false) + end + + it 'renames' do + expect { service.execute(protected_branch) }.to change { + protected_branch.reload.name + }.to(branch_name.reverse) + end + end + end + + include_context 'with scan result policy blocking protected branches' do + include_examples 'prevents update of protected branch' + end + + include_context 'with scan result policy blocking group-level protected branches' do + include_examples 'prevents update of protected branch' + end + end + end + end end diff --git a/lib/gitlab/ci/config/interpolation/block.rb b/lib/gitlab/ci/config/interpolation/block.rb index aec19299e86feca4263ce6b8981aacc01f14b4d1..dc1ca423a81673c821532b5b6b42966551384174 100644 --- a/lib/gitlab/ci/config/interpolation/block.rb +++ b/lib/gitlab/ci/config/interpolation/block.rb @@ -14,7 +14,7 @@ module Interpolation # they are presented. class Block PREFIX = '$[[' - PATTERN = /(?<block>\$\[\[\s*(?<data>.*?)\s*\]\])/ + PATTERN = /(?<block>\$\[\[\s*(?<data>\S{1}.*?\S{1})\s*\]\])/ MAX_FUNCTIONS = 3 attr_reader :block, :data, :ctx, :errors diff --git a/spec/lib/gitlab/ci/config/interpolation/block_spec.rb b/spec/lib/gitlab/ci/config/interpolation/block_spec.rb index bfaa4eb3e05652f1f4da954d5b1d5fb407c9f432..7b9111f11d373b52bf60cbe41bf07ec090fa37ad 100644 --- a/spec/lib/gitlab/ci/config/interpolation/block_spec.rb +++ b/spec/lib/gitlab/ci/config/interpolation/block_spec.rb @@ -31,9 +31,9 @@ .to yield_successive_args(['$[[ access1 ]]', 'access1'], ['$[[ access2 ]]', 'access2']) end - it 'matches an empty block' do + it 'does not match an empty block' do expect { |b| described_class.match('$[[]]', &b) } - .to yield_with_args('$[[]]', '') + .not_to yield_with_args(anything) end context 'when functions are specified in the block' do diff --git a/spec/support/shared_examples/services/protected_branches_shared_examples.rb b/spec/support/shared_examples/services/protected_branches_shared_examples.rb index 980241ad586fe0bc254205dc284c4ca2428675e2..74bf57ea5ea2abbdf63d96dbb30021be4c9de691 100644 --- a/spec/support/shared_examples/services/protected_branches_shared_examples.rb +++ b/spec/support/shared_examples/services/protected_branches_shared_examples.rb @@ -30,6 +30,14 @@ end end +RSpec.shared_context 'with scan result policy blocking group-level protected branches' do + include_context 'with scan result policy' do + let(:scan_result_policy) do + build(:scan_result_policy, branches: [branch_name], approval_settings: { block_group_branch_modification: true }) + end + end +end + RSpec.shared_context 'with scan result policy preventing force pushing' do include_context 'with scan result policy' do let(:prevent_pushing_and_force_pushing) { true }