From c1ed6d2b35153c613a11ea0cd00b63958db2b79e Mon Sep 17 00:00:00 2001 From: Sashi Kumar Kumaresan <skumar@gitlab.com> Date: Tue, 3 Jan 2023 18:49:50 +0000 Subject: [PATCH] Delete project specific licenses when license policy is deleted Merge branch 'security-shared-project-license-policy-15-6' into 'master' See merge request gitlab-org/security/gitlab!2894 Changelog: security --- ee/app/models/software_license_policy.rb | 1 + .../delete_service.rb | 18 +++++++ ee/lib/api/managed_licenses.rb | 4 +- .../models/software_license_policy_spec.rb | 8 +++ ee/spec/requests/api/managed_licenses_spec.rb | 1 + .../delete_service_spec.rb | 53 +++++++++++++++++++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 ee/app/services/software_license_policies/delete_service.rb create mode 100644 ee/spec/services/software_license_policies/delete_service_spec.rb diff --git a/ee/app/models/software_license_policy.rb b/ee/app/models/software_license_policy.rb index 66393086cc43d..9552102ca0010 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 0000000000000..d1a8e91e89caa --- /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 df3afdbc62e67..b4ad074cc8cfd 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 616c0d7624c96..eeafe3969606a 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 60961eeb438c8..d3e99ef852669 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 0000000000000..e855b98accd77 --- /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 -- GitLab