diff --git a/ee/app/models/software_license_policy.rb b/ee/app/models/software_license_policy.rb index 66393086cc43d65c54e5216157739cffc7a7b3dd..9552102ca00106ed32b28757fe4c8d1a7503b0ce 100644 --- a/ee/app/models/software_license_policy.rb +++ b/ee/app/models/software_license_policy.rb @@ -33,6 +33,7 @@ class SoftwareLicensePolicy < ApplicationRecord scope :with_license, -> { joins(:software_license) } scope :including_license, -> { includes(:software_license) } scope :unreachable_limit, -> { limit(1_000) } + scope :count_for_software_license, ->(software_license_id) { where(software_license_id: software_license_id).count } scope :with_license_by_name, -> (license_name) do with_license.where(SoftwareLicense.arel_table[:name].lower.in(Array(license_name).map(&:downcase))) diff --git a/ee/app/services/software_license_policies/delete_service.rb b/ee/app/services/software_license_policies/delete_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..d1a8e91e89caa23b16bb61e261ee0cfd58d6c6b8 --- /dev/null +++ b/ee/app/services/software_license_policies/delete_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SoftwareLicensePolicies + class DeleteService < ::BaseService + def execute(software_license_policy) + SoftwareLicensePolicy.transaction do + software_license = SoftwareLicense.find(software_license_policy.software_license_id) + + software_license_policy.destroy! + + if software_license.spdx_identifier.nil? && + SoftwareLicensePolicy.count_for_software_license(software_license.id) == 0 + software_license.destroy! + end + end + end + end +end diff --git a/ee/lib/api/managed_licenses.rb b/ee/lib/api/managed_licenses.rb index df3afdbc62e67329a3ecda52e0f5a1b83c1c6b81..b4ad074cc8cfd9a33fa9afdc609f53ffa0389106 100644 --- a/ee/lib/api/managed_licenses.rb +++ b/ee/lib/api/managed_licenses.rb @@ -146,7 +146,9 @@ def authorize_can_admin! authorize_can_admin! not_found!('SoftwareLicensePolicy') unless software_license_policy - software_license_policy.destroy! + SoftwareLicensePolicies::DeleteService + .new(user_project, current_user) + .execute(software_license_policy) no_content! end diff --git a/ee/spec/models/software_license_policy_spec.rb b/ee/spec/models/software_license_policy_spec.rb index 616c0d7624c9641ec5bff3979867a3ca15818257..eeafe3969606af6566d8bbeb8cfb960531c7cb1a 100644 --- a/ee/spec/models/software_license_policy_spec.rb +++ b/ee/spec/models/software_license_policy_spec.rb @@ -45,6 +45,14 @@ it { expect(described_class.by_spdx(SecureRandom.uuid)).to be_empty } end + describe '.count_for_software_license' do + let!(:mit) { create(:software_license, :mit) } + let!(:mit_policy1) { create(:software_license_policy, software_license: mit) } + let!(:mit_policy2) { create(:software_license_policy, software_license: mit) } + + it { expect(described_class.count_for_software_license(mit.id)).to eq(2) } + end + describe "#name" do specify { expect(subject.name).to eql(subject.software_license.name) } end diff --git a/ee/spec/requests/api/managed_licenses_spec.rb b/ee/spec/requests/api/managed_licenses_spec.rb index 60961eeb438c85fe0c6f6047b5f1ef27c1f75dba..d3e99ef8526692ee15b28b550d99d5f65159af4d 100644 --- a/ee/spec/requests/api/managed_licenses_spec.rb +++ b/ee/spec/requests/api/managed_licenses_spec.rb @@ -271,6 +271,7 @@ expect(response).to have_gitlab_http_status(:no_content) end.to change { project.software_license_policies.count }.by(-1) + .and change { SoftwareLicense.count }.by(-1) end it 'responds with 404 Not Found if requesting non-existing managed license' do diff --git a/ee/spec/services/software_license_policies/delete_service_spec.rb b/ee/spec/services/software_license_policies/delete_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..e855b98accd77f7ebfe86f9b20b79fecaef949eb --- /dev/null +++ b/ee/spec/services/software_license_policies/delete_service_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SoftwareLicensePolicies::DeleteService, feature_category: :security_policy_management do + subject(:service) { described_class.new(project, user) } + + let_it_be(:project) { create(:project) } + + let(:user) do + create(:user).tap do |u| + project.add_maintainer(u) + end + end + + let(:software_license) { create(:software_license) } + let(:software_license_policy) { create(:software_license_policy, :denied, software_license: software_license) } + + describe '#execute' do + context 'when software_license has one software_license_policy' do + it 'deletes software_license_policy and software_license' do + service.execute(software_license_policy) + + expect { software_license_policy.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { software_license.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + context 'when software_license has spdx_identifier' do + let(:software_license) { create(:software_license, :mit) } + + it 'deletes software_license_policy only' do + service.execute(software_license_policy) + + expect { software_license_policy.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { software_license.reload }.not_to raise_error + end + end + + context 'when software_license has multiple software_license_policies' do + before do + create(:software_license_policy, software_license: software_license) + end + + it 'deletes software_license_policy only' do + service.execute(software_license_policy) + + expect { software_license_policy.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { software_license.reload }.not_to raise_error + end + end + end +end