Commit aa3d11cf authored by Tetiana Chupryna's avatar Tetiana Chupryna Committed by Dmytro Zaporozhets

Prevent merge if denied licenses are found

parent 3b291822
......@@ -102,6 +102,7 @@ module EE
override :mergeable?
def mergeable?(skip_ci_check: false)
return false unless approved?
return false if has_denied_policies?
return false if merge_blocked_by_other_mrs?
super
......@@ -144,6 +145,13 @@ module EE
hidden.count
end
def has_denied_policies?
return false if ::Feature.disabled?(:license_compliance_denies_mr, project, default_enabled: false)
return false unless has_license_scanning_reports?
actual_head_pipeline.license_scanning_report.violates?(project.software_license_policies)
end
def enabled_reports
{
sast: report_type_enabled?(:sast),
......
......@@ -8,6 +8,10 @@ module EE
expose :merge_train_when_pipeline_succeeds_docs_path do |merge_request|
presenter(merge_request).merge_train_when_pipeline_succeeds_docs_path
end
expose :policy_violation do |merge_request|
presenter(merge_request).has_denied_policies?
end
end
end
end
---
title: Prevent MR from merging if denied licenses are found
merge_request: 34413
author:
type: added
......@@ -4,7 +4,8 @@
{ "$ref": "../../../../../../spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json" },
{
"properties" : {
"merge_train_when_pipeline_succeeds_docs_path": { "type": "string" }
"merge_train_when_pipeline_succeeds_docs_path": { "type": "string" },
"policy_violation": { "type": "boolean" }
}
}
]
......
......@@ -64,6 +64,63 @@ RSpec.describe MergeRequest do
end
end
describe '#has_denied_policies?' do
subject { merge_request.has_denied_policies? }
context 'without existing pipeline' do
it { is_expected.to be_falsey }
end
context 'with existing pipeline' do
before do
stub_licensed_features(license_scanning: true)
end
context 'without license_scanning report' do
let(:merge_request) { create(:ee_merge_request, :with_dependency_scanning_reports, source_project: project) }
it { is_expected.to be_falsey }
end
context 'with license_scanning report' do
let(:merge_request) { create(:ee_merge_request, :with_license_scanning_reports, source_project: project) }
let(:mit_license) { build(:software_license, :mit, spdx_identifier: nil) }
context 'without denied policy' do
it { is_expected.to be_falsey }
end
context 'with allowed policy' do
let(:allowed_policy) { build(:software_license_policy, :allowed, software_license: mit_license) }
before do
project.software_license_policies << allowed_policy
end
it { is_expected.to be_falsey }
end
context 'with denied policy' do
let(:denied_policy) { build(:software_license_policy, :denied, software_license: mit_license) }
before do
project.software_license_policies << denied_policy
end
it { is_expected.to be_truthy }
context 'with disabled licensed feature' do
before do
stub_licensed_features(license_scanning: false)
end
it { is_expected.to be_falsey }
end
end
end
end
end
describe '#enabled_reports' do
let(:project) { create(:project, :repository) }
......@@ -693,28 +750,64 @@ RSpec.describe MergeRequest do
end
describe '#mergeable?' do
let(:project) { create(:project) }
subject { create(:merge_request, source_project: project) }
subject { merge_request.mergeable? }
context 'when using approvals' do
let(:user) { create(:user) }
before do
allow(subject).to receive(:mergeable_state?).and_return(true)
allow(merge_request).to receive(:mergeable_state?).and_return(true)
subject.target_project.update(approvals_before_merge: 1)
merge_request.target_project.update(approvals_before_merge: 1)
project.add_developer(user)
end
it 'return false if not approved' do
expect(subject.mergeable?).to be_falsey
is_expected.to be_falsey
end
it 'return true if approved' do
subject.approvals.create(user: user)
merge_request.approvals.create(user: user)
is_expected.to be_truthy
end
end
expect(subject.mergeable?).to be_truthy
context 'when running license_scanning ci job' do
context 'when merge request has denied policies' do
before do
allow(merge_request).to receive(:has_denied_policies?).and_return(true)
end
context 'when approval is required and granted' do
before do
allow(merge_request).to receive(:approved?).and_return(true)
end
it 'is not mergeable' do
is_expected.to be_falsey
end
end
context 'when is not approved' do
before do
allow(merge_request).to receive(:approved?).and_return(false)
end
it 'is not mergeable' do
is_expected.to be_falsey
end
end
end
context 'when merge request has no denied policies' do
before do
allow(merge_request).to receive(:has_denied_policies?).and_return(false)
end
it 'is mergeable' do
is_expected.to be_truthy
end
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MergeRequestPollCachedWidgetEntity do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:resource) { create(:merge_request, source_project: project, target_project: project) }
let_it_be(:user) { create(:user) }
let(:request) { double('request', current_user: user, project: project) }
subject { described_class.new(resource, request: request).as_json }
it 'includes docs path for merge trains' do
is_expected.to include(:merge_train_when_pipeline_succeeds_docs_path)
end
it 'includes policy violation status' do
is_expected.to include(:policy_violation)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment