Commit 8854f527 authored by Imre Farkas's avatar Imre Farkas

Merge branch '14061-policies-filter' into 'master'

Filter software license policies by classification

See merge request gitlab-org/gitlab!22554
parents d4278239 1acf94ba
...@@ -65,12 +65,20 @@ module Projects ...@@ -65,12 +65,20 @@ module Projects
render json: { errors: result[:message].as_json }, status: result.fetch(:http_status, :unprocessable_entity) render json: { errors: result[:message].as_json }, status: result.fetch(:http_status, :unprocessable_entity)
end end
def matching_policies_params
params.permit(:detected, classification: [])
end
def matching_policies_from(license_compliance) def matching_policies_from(license_compliance)
if params[:detected] filters = matching_policies_params
license_compliance.detected_policies license_compliance.find_policies(
else detected_only: truthy?(filters[:detected]),
license_compliance.policies classification: filters[:classification]
)
end end
def truthy?(value)
value.in?(%w[true 1])
end end
end end
end end
...@@ -14,8 +14,12 @@ module SCA ...@@ -14,8 +14,12 @@ module SCA
end end
end end
def detected_policies def find_policies(detected_only: false, classification: [])
policies.reject { |policy| policy.dependencies.count.zero? } classifications = Array(classification || [])
policies.reject do |policy|
(detected_only && policy.dependencies.none?) ||
(classifications.present? && !policy.classification.in?(classifications))
end
end end
def latest_build_for_default_branch def latest_build_for_default_branch
......
...@@ -84,7 +84,11 @@ describe Projects::LicensesController do ...@@ -84,7 +84,11 @@ describe Projects::LicensesController do
context "when loading all policies" do context "when loading all policies" do
before do before do
get :index, params: { namespace_id: project.namespace, project_id: project }, format: :json get :index, params: {
namespace_id: project.namespace,
project_id: project,
detected: false
}, format: :json
end end
it { expect(response).to have_http_status(:ok) } it { expect(response).to have_http_status(:ok) }
...@@ -172,6 +176,56 @@ describe Projects::LicensesController do ...@@ -172,6 +176,56 @@ describe Projects::LicensesController do
}) })
end end
end end
context "when loading `allowed` software policies only" do
before do
get :index, params: {
namespace_id: project.namespace,
project_id: project,
classification: ['allowed']
}, format: :json
end
it { expect(response).to have_http_status(:ok) }
it { expect(json_response["licenses"].count).to be(1) }
it 'includes only `allowed` policies' do
expect(json_response.dig("licenses", 0)).to include({
"id" => other_license_policy.id,
"spdx_identifier" => "Other-Id",
"classification" => "allowed"
})
end
end
context "when loading `allowed` and `denied` software policies" do
before do
get :index, params: {
namespace_id: project.namespace,
project_id: project,
classification: %w[allowed denied]
}, format: :json
end
it { expect(response).to have_http_status(:ok) }
it { expect(json_response["licenses"].count).to be(2) }
it 'includes `denied` policies' do
expect(json_response.dig("licenses", 0)).to include({
"id" => mit_policy.id,
"spdx_identifier" => mit.spdx_identifier,
"classification" => mit_policy.classification
})
end
it 'includes `allowed` policies' do
expect(json_response.dig("licenses", 1)).to include({
"id" => other_license_policy.id,
"spdx_identifier" => other_license_policy.spdx_identifier,
"classification" => other_license_policy.classification
})
end
end
end end
context 'without existing report' do context 'without existing report' do
......
...@@ -147,38 +147,113 @@ RSpec.describe SCA::LicenseCompliance do ...@@ -147,38 +147,113 @@ RSpec.describe SCA::LicenseCompliance do
end end
end end
describe "#detected_policies" do describe "#find_policies" do
let!(:pipeline) { create(:ci_pipeline, :success, project: project, builds: [create(:ee_ci_build, :success, :license_scan_v2)]) } let!(:pipeline) { create(:ci_pipeline, :success, project: project, builds: [create(:ee_ci_build, :success, :license_scan_v2)]) }
let!(:mit_policy) { create(:software_license_policy, :denied, software_license: mit, project: project) } let!(:mit_policy) { create(:software_license_policy, :denied, software_license: mit, project: project) }
let!(:other_license_policy) { create(:software_license_policy, :allowed, software_license: other_license, project: project) } let!(:other_license_policy) { create(:software_license_policy, :allowed, software_license: other_license, project: project) }
let(:results) { subject.detected_policies }
it 'excludes policies for licenses that do not appear in the latest license scan report' do def assert_matches(item, expected = {})
expect(results.count).to eq(3) actual = expected.keys.each_with_object({}) do |attribute, memo|
memo[attribute] = item.public_send(attribute)
end
expect(actual).to eql(expected)
end
context "when searching for policies for licenses that were detected in a scan report" do
let(:results) { subject.find_policies(detected_only: true) }
it 'only includes licenses that appear in the latest license scan report' do
expect(results.count).to be(3)
end end
it 'includes a policy for an unclassified and known license that was detected in the scan report' do it 'includes a policy for an unclassified and known license that was detected in the scan report' do
expect(results[0].id).to be_nil assert_matches(
expect(results[0].name).to eq("BSD 3-Clause \"New\" or \"Revised\" License") results[0],
expect(results[0].url).to eq("http://spdx.org/licenses/BSD-3-Clause.json") id: nil,
expect(results[0].classification).to eq("unclassified") name: 'BSD 3-Clause "New" or "Revised" License',
expect(results[0].spdx_identifier).to eq("BSD-3-Clause") url: "http://spdx.org/licenses/BSD-3-Clause.json",
classification: "unclassified",
spdx_identifier: "BSD-3-Clause"
)
end end
it 'includes an entry for a denied license found in the scan report' do it 'includes an entry for a denied license found in the scan report' do
expect(results[1].id).to eq(mit_policy.id) assert_matches(
expect(results[1].name).to eq(mit.name) results[1],
expect(results[1].url).to eq("http://spdx.org/licenses/MIT.json") id: mit_policy.id,
expect(results[1].classification).to eq("denied") name: mit.name,
expect(results[1].spdx_identifier).to eq("MIT") url: "http://spdx.org/licenses/MIT.json",
classification: "denied",
spdx_identifier: "MIT"
)
end end
it 'includes an entry for an allowed license found in the scan report' do it 'includes an entry for an allowed license found in the scan report' do
expect(results[2].id).to be_nil assert_matches(
expect(results[2].name).to eq("unknown") results[2],
expect(results[2].url).to be_blank id: nil,
expect(results[2].classification).to eq("unclassified") name: 'unknown',
expect(results[2].spdx_identifier).to be_nil url: '',
classification: 'unclassified',
spdx_identifier: nil
)
end
end
context "when searching for policies with a specific classification" do
let(:results) { subject.find_policies(classification: ['allowed']) }
it 'includes an entry for each `allowed` licensed' do
expect(results.count).to eq(1)
assert_matches(
results[0],
id: other_license_policy.id,
name: other_license_policy.software_license.name,
url: nil,
classification: 'allowed',
spdx_identifier: other_license_policy.software_license.spdx_identifier
)
end
end
context "when searching for policies by multiple classifications" do
let(:results) { subject.find_policies(classification: %w[allowed denied]) }
it 'includes an entry for each `allowed` and `denied` licensed' do
expect(results.count).to eq(2)
assert_matches(
results[0],
id: mit_policy.id,
name: mit_policy.software_license.name,
url: 'http://spdx.org/licenses/MIT.json',
classification: "denied",
spdx_identifier: mit_policy.software_license.spdx_identifier
)
assert_matches(
results[1],
id: other_license_policy.id,
name: other_license_policy.software_license.name,
url: nil,
classification: "allowed",
spdx_identifier: other_license_policy.software_license.spdx_identifier
)
end
end
context "when searching for detected policies matching a classification" do
let(:results) { subject.find_policies(detected_only: true, classification: %w[allowed denied]) }
it 'includes an entry for each entry that was detected in the report and matches a classification' do
expect(results.count).to eq(1)
assert_matches(
results[0],
id: mit_policy.id,
name: mit_policy.software_license.name,
url: 'http://spdx.org/licenses/MIT.json',
classification: "denied",
spdx_identifier: mit_policy.software_license.spdx_identifier
)
end
end end
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