diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-17 09:07:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-17 09:07:23 +0300 |
commit | 172e4a12748fd146fdd0e9eca12ade4c51dabda9 (patch) | |
tree | 7d4be9fa2966dbaf4f9f98937db051627e78b816 /spec | |
parent | 4c872af312f27f2e2da967a6efebd76e88119caa (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/factories/ci/reports/sbom/components.rb | 6 | ||||
-rw-r--r-- | spec/graphql/types/ci/pipeline_type_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/bitbucket_server/connection_spec.rb | 108 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/parsers/sbom/component_spec.rb | 96 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb | 92 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/reports/sbom/component_spec.rb | 57 |
6 files changed, 243 insertions, 118 deletions
diff --git a/spec/factories/ci/reports/sbom/components.rb b/spec/factories/ci/reports/sbom/components.rb index 76bfbe13acb..231fefff99c 100644 --- a/spec/factories/ci/reports/sbom/components.rb +++ b/spec/factories/ci/reports/sbom/components.rb @@ -10,6 +10,7 @@ FactoryBot.define do transient do purl_type { 'npm' } namespace { nil } + source_package_name { nil } end purl do @@ -18,7 +19,7 @@ FactoryBot.define do name: name, namespace: namespace, version: version - ).to_s + ) end skip_create @@ -28,7 +29,8 @@ FactoryBot.define do type: type, name: name, purl: purl, - version: version + version: version, + source_package_name: source_package_name ) end end diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb index 26dfc0b10c6..45fe33f34a1 100644 --- a/spec/graphql/types/ci/pipeline_type_spec.rb +++ b/spec/graphql/types/ci/pipeline_type_spec.rb @@ -16,7 +16,7 @@ RSpec.describe Types::Ci::PipelineType do upstream path project active user_permissions warnings commit commit_path uses_needs test_report_summary test_suite ref ref_path warning_messages merge_request_event_type name total_jobs triggered_by_path child source stuck - latest merge_request ref_text failure_reason + latest merge_request ref_text failure_reason yaml_errors trigger ] if Gitlab.ee? diff --git a/spec/lib/bitbucket_server/connection_spec.rb b/spec/lib/bitbucket_server/connection_spec.rb index 59eda91285f..68b35979955 100644 --- a/spec/lib/bitbucket_server/connection_spec.rb +++ b/spec/lib/bitbucket_server/connection_spec.rb @@ -22,32 +22,28 @@ RSpec.describe BitbucketServer::Connection, feature_category: :importers do subject.get(url) end - shared_examples 'handles get requests' do - it 'returns JSON body' do - expect(subject.get(url, { something: 1 })).to eq(payload) - end + it 'returns JSON body' do + expect(subject.get(url, { something: 1 })).to eq(payload) + end - it 'throws an exception if the response is not 200' do - WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_return(body: payload.to_json, status: 500, headers: headers) + it 'throws an exception if the response is not 200' do + WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_return(body: payload.to_json, status: 500, headers: headers) - expect { subject.get(url) }.to raise_error(described_class::ConnectionError) - end + expect { subject.get(url) }.to raise_error(described_class::ConnectionError) + end - it 'throws an exception if the response is not JSON' do - WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_return(body: 'bad data', status: 200, headers: headers) + it 'throws an exception if the response is not JSON' do + WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_return(body: 'bad data', status: 200, headers: headers) - expect { subject.get(url) }.to raise_error(described_class::ConnectionError) - end + expect { subject.get(url) }.to raise_error(described_class::ConnectionError) + end - it 'throws an exception upon a network error' do - WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_raise(OpenSSL::SSL::SSLError) + it 'throws an exception upon a network error' do + WebMock.stub_request(:get, url).with(headers: { 'Accept' => 'application/json' }).to_raise(OpenSSL::SSL::SSLError) - expect { subject.get(url) }.to raise_error(described_class::ConnectionError) - end + expect { subject.get(url) }.to raise_error(described_class::ConnectionError) end - it_behaves_like 'handles get requests' - context 'when the response is a 429 rate limit reached error' do let(:response) do instance_double(HTTParty::Response, parsed_response: payload, code: 429, headers: headers.merge('retry-after' => '0')) @@ -65,14 +61,6 @@ RSpec.describe BitbucketServer::Connection, feature_category: :importers do expect { subject.get(url) }.to raise_error(BitbucketServer::Connection::ConnectionError) end end - - context 'when the bitbucket_server_importer_exponential_backoff feature flag is disabled' do - before do - stub_feature_flags(bitbucket_server_importer_exponential_backoff: false) - end - - it_behaves_like 'handles get requests' - end end describe '#post' do @@ -88,38 +76,26 @@ RSpec.describe BitbucketServer::Connection, feature_category: :importers do subject.post(url, payload) end - shared_examples 'handles post requests' do - it 'returns JSON body' do - expect(subject.post(url, payload)).to eq(payload) - end - - it 'throws an exception if the response is not 200' do - WebMock.stub_request(:post, url).with(headers: headers).to_return(body: payload.to_json, status: 500, headers: headers) - - expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) - end + it 'returns JSON body' do + expect(subject.post(url, payload)).to eq(payload) + end - it 'throws an exception upon a network error' do - WebMock.stub_request(:post, url).with(headers: { 'Accept' => 'application/json' }).to_raise(OpenSSL::SSL::SSLError) + it 'throws an exception if the response is not 200' do + WebMock.stub_request(:post, url).with(headers: headers).to_return(body: payload.to_json, status: 500, headers: headers) - expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) - end + expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) + end - it 'throws an exception if the URI is invalid' do - stub_request(:post, url).with(headers: { 'Accept' => 'application/json' }).to_raise(URI::InvalidURIError) + it 'throws an exception upon a network error' do + WebMock.stub_request(:post, url).with(headers: { 'Accept' => 'application/json' }).to_raise(OpenSSL::SSL::SSLError) - expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) - end + expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) end - it_behaves_like 'handles post requests' - - context 'when the bitbucket_server_importer_exponential_backoff feature flag is disabled' do - before do - stub_feature_flags(bitbucket_server_importer_exponential_backoff: false) - end + it 'throws an exception if the URI is invalid' do + stub_request(:post, url).with(headers: { 'Accept' => 'application/json' }).to_raise(URI::InvalidURIError) - it_behaves_like 'handles post requests' + expect { subject.post(url, payload) }.to raise_error(described_class::ConnectionError) end end @@ -141,32 +117,20 @@ RSpec.describe BitbucketServer::Connection, feature_category: :importers do subject.delete(:branches, branch_path, payload) end - shared_examples 'handles delete requests' do - it 'returns JSON body' do - expect(subject.delete(:branches, branch_path, payload)).to eq(payload) - end - - it 'throws an exception if the response is not 200' do - WebMock.stub_request(:delete, branch_url).with(headers: headers).to_return(body: payload.to_json, status: 500, headers: headers) - - expect { subject.delete(:branches, branch_path, payload) }.to raise_error(described_class::ConnectionError) - end + it 'returns JSON body' do + expect(subject.delete(:branches, branch_path, payload)).to eq(payload) + end - it 'throws an exception upon a network error' do - WebMock.stub_request(:delete, branch_url).with(headers: headers).to_raise(OpenSSL::SSL::SSLError) + it 'throws an exception if the response is not 200' do + WebMock.stub_request(:delete, branch_url).with(headers: headers).to_return(body: payload.to_json, status: 500, headers: headers) - expect { subject.delete(:branches, branch_path, payload) }.to raise_error(described_class::ConnectionError) - end + expect { subject.delete(:branches, branch_path, payload) }.to raise_error(described_class::ConnectionError) end - it_behaves_like 'handles delete requests' - - context 'with the bitbucket_server_importer_exponential_backoff feature flag disabled' do - before do - stub_feature_flags(bitbucket_server_importer_exponential_backoff: false) - end + it 'throws an exception upon a network error' do + WebMock.stub_request(:delete, branch_url).with(headers: headers).to_raise(OpenSSL::SSL::SSLError) - it_behaves_like 'handles delete requests' + expect { subject.delete(:branches, branch_path, payload) }.to raise_error(described_class::ConnectionError) end end end diff --git a/spec/lib/gitlab/ci/parsers/sbom/component_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/component_spec.rb new file mode 100644 index 00000000000..17cc3fb21f5 --- /dev/null +++ b/spec/lib/gitlab/ci/parsers/sbom/component_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Parsers::Sbom::Component, feature_category: :dependency_management do + describe "#parse" do + subject(:component) { described_class.new(data).parse } + + context "with dependency scanning component" do + let(:data) do + { + "name" => "activesupport", + "version" => "5.1.4", + "purl" => "pkg:gem/activesupport@5.1.4", + "type" => "library", + "bom-ref" => "pkg:gem/activesupport@5.1.4" + } + end + + it "sets the expected values" do + is_expected.to be_kind_of(::Gitlab::Ci::Reports::Sbom::Component) + + expect(component.component_type).to eq("library") + expect(component.name).to eq("activesupport") + expect(component.version).to eq("5.1.4") + expect(component.purl).to be_kind_of(::Sbom::PackageUrl) + expect(component.purl.name).to eq("activesupport") + expect(component.properties).to be_nil + expect(component.source_package_name).to be_nil + end + end + + context "with container scanning component" do + let(:property_name) { 'aquasecurity:trivy:PkgType' } + let(:property_value) { 'alpine' } + let(:purl) { "pkg:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.4" } + let(:data) do + { + "name" => "alpine-baselayout-data", + "version" => "3.4.3-r1", + "purl" => purl, + "type" => "library", + "bom-ref" => purl, + "properties" => [ + { + "name" => property_name, + "value" => property_value + } + ] + } + end + + context "with an aquasecurity:trivy:SrcName property" do + let(:property_name) { "aquasecurity:trivy:SrcName" } + let(:property_value) { "alpine-baselayout" } + + it "sets properties field with parsed data" do + property_data = component.properties.data + + expect(property_data).to match({ "SrcName" => "alpine-baselayout" }) + end + + it "sets the source_package_name from the aquasecurity:trivy:SrcName property" do + expect(component.source_package_name).to eq(property_value) + end + end + + context "without an aquasecurity:trivy:SrcName property" do + it "sets properties field with parsed data" do + property_data = component.properties.data + + expect(property_data).to match({ "PkgType" => "alpine" }) + end + + it "sets the source_package_name from the component name" do + expect(component.source_package_name).to eq("alpine-baselayout-data") + end + end + + context "without properties" do + it "sets the source_package_name from the component name" do + data.delete('properties') + expect(component.source_package_name).to eq("alpine-baselayout-data") + end + end + + context "with corrupted purl" do + let(:purl) { "unknown:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.4" } + + it "raises an error" do + expect { component }.to raise_error(::Sbom::PackageUrl::InvalidPackageUrl) + end + end + end + end +end diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb index 6a6fe59bce1..0c9a6be7100 100644 --- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb +++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen let(:raw_report_data) { report_data.to_json } let(:report_valid?) { true } let(:validator_errors) { [] } - let(:properties_parser) { class_double('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties') } + let(:properties_parser) { Gitlab::Ci::Parsers::Sbom::CyclonedxProperties } let(:uuid) { 'c9d550a3-feb8-483b-a901-5aa892d039f9' } let(:base_report_data) do @@ -28,8 +28,6 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen allow(validator).to receive(:errors).and_return(validator_errors) end - allow(properties_parser).to receive(:parse_source) - stub_const('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties', properties_parser) allow(SecureRandom).to receive(:uuid).and_return(uuid) end @@ -65,8 +63,9 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen end end - context 'when report has components' do + context 'when report has dependency_scanning components' do let(:report_data) { base_report_data.merge({ 'components' => components }) } + let(:components) do [ { @@ -128,8 +127,8 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen context 'when component is trivy type' do let(:parsed_properties) do { - 'PkgID' => 'adduser@3.134', - 'PkgType' => 'debian' + 'PkgID' => 'activesupport@5.1.4', + 'PkgType' => 'gem' } end @@ -144,28 +143,25 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen "properties" => [ { "name" => "aquasecurity:trivy:PkgID", - "value" => "apt@2.6.1" + "value" => "activesupport@5.1.4" }, { "name" => "aquasecurity:trivy:PkgType", - "value" => "debian" + "value" => "gem" } ] } ] end - before do - allow(properties_parser).to receive(:parse_trivy_source).and_return(parsed_properties) - stub_const('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties', properties_parser) - end - it 'adds each component, ignoring unused attributes' do expect(report).to receive(:add_component) .with( an_object_having_attributes( component_type: "library", - properties: parsed_properties, + properties: an_object_having_attributes( + data: parsed_properties + ), purl: an_object_having_attributes( type: "gem" ) @@ -195,6 +191,74 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen end end + context 'when report has container_scanning components' do + let(:report_data) { base_report_data.merge({ 'components' => components }) } + + let(:parsed_properties) do + { + 'SrcName' => 'alpine-baselayout' + } + end + + let(:components) do + [ + { + "name" => "alpine", + "version" => "3.4.3-r1", + "purl" => "pkg:apk/alpine/alpine@3.4.3-r1?arch=x86_64&distro=3.18.4", + "type" => "library", + "bom-ref" => "pkg:apk/alpine/alpine@3.4.3-r1?arch=x86_64&distro=3.18.4" + }, + { + "name" => "alpine-baselayout-data", + "version" => "3.4.3-r1", + "purl" => "pkg:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.4", + "type" => "library", + "bom-ref" => "pkg:apk/alpine/alpine-baselayout-data@3.4.3-r1?arch=x86_64&distro=3.18.4", + "properties" => [ + { + "name" => "aquasecurity:trivy:SrcName", + "value" => "alpine-baselayout" + } + ] + } + ] + end + + before do + allow(report).to receive(:add_component) + end + + it 'adds each component, ignoring unused attributes' do + expect(report).to receive(:add_component) + .with( + an_object_having_attributes( + name: "alpine/alpine", + version: "3.4.3-r1", + component_type: "library", + purl: an_object_having_attributes(type: "apk"), + properties: nil, + source_package_name: 'alpine' + ) + ) + expect(report).to receive(:add_component) + .with( + an_object_having_attributes( + name: "alpine/alpine-baselayout-data", + version: "3.4.3-r1", + component_type: "library", + purl: an_object_having_attributes(type: "apk"), + properties: an_object_having_attributes( + data: parsed_properties + ), + source_package_name: 'alpine-baselayout' + ) + ) + + parse! + end + end + context 'when report has metadata tools, author and properties' do let(:report_data) { base_report_data.merge(metadata) } diff --git a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb index 4c9fd00f96a..242c9e4071b 100644 --- a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb +++ b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb @@ -6,15 +6,17 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen let(:component_type) { 'library' } let(:name) { 'component-name' } let(:purl_type) { 'npm' } - let(:purl) { Sbom::PackageUrl.new(type: purl_type, name: name, version: version).to_s } + let(:purl) { Sbom::PackageUrl.new(type: purl_type, name: name, version: version) } let(:version) { 'v0.0.1' } + let(:source_package_name) { 'source-component' } subject(:component) do described_class.new( type: component_type, name: name, purl: purl, - version: version + version: version, + source_package_name: source_package_name ) end @@ -23,7 +25,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen component_type: component_type, name: name, purl: an_object_having_attributes(type: purl_type), - version: version + version: version, + source_package_name: source_package_name ) end @@ -34,18 +37,10 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen context 'with namespace' do let(:purl) do - 'pkg:maven/org.NameSpace/Name@v0.0.1' + Sbom::PackageUrl.new(type: 'maven', namespace: 'org.NameSpace', name: 'Name', version: 'v0.0.1') end it { is_expected.to eq('org.NameSpace/Name') } - - context 'when needing normalization' do - let(:purl) do - 'pkg:pypi/org.NameSpace/Name@v0.0.1' - end - - it { is_expected.to eq('org.namespace/name') } - end end end @@ -63,14 +58,18 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen describe '#<=>' do where do + purl_a = Sbom::PackageUrl.new(type: 'npm', name: 'component-a', version: '1.0.0') + purl_b = Sbom::PackageUrl.new(type: 'npm', name: 'component-b', version: '1.0.0') + purl_composer = Sbom::PackageUrl.new(type: 'composer', name: 'component-a', version: '1.0.0') + { 'equal' => { a_name: 'component-a', b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_a, + b_purl: purl_a, a_version: '1.0.0', b_version: '1.0.0', expected: 0 @@ -80,8 +79,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-b', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:npm/component-b@1.0.0', + a_purl: purl_a, + b_purl: purl_b, a_version: '1.0.0', b_version: '1.0.0', expected: -1 @@ -91,8 +90,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-b@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_b, + b_purl: purl_a, a_version: '1.0.0', b_version: '1.0.0', expected: 1 @@ -102,8 +101,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:composer/component-a@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_composer, + b_purl: purl_a, a_version: '1.0.0', b_version: '1.0.0', expected: -1 @@ -113,8 +112,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:composer/component-a@1.0.0', + a_purl: purl_a, + b_purl: purl_composer, a_version: '1.0.0', b_version: '1.0.0', expected: 1 @@ -125,7 +124,7 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen a_type: 'library', b_type: 'library', a_purl: nil, - b_purl: 'pkg:npm/component-a@1.0.0', + b_purl: purl_a, a_version: '1.0.0', b_version: '1.0.0', expected: -1 @@ -135,8 +134,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_a, + b_purl: purl_a, a_version: '1.0.0', b_version: '2.0.0', expected: -1 @@ -146,8 +145,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_a, + b_purl: purl_a, a_version: '2.0.0', b_version: '1.0.0', expected: 1 @@ -157,8 +156,8 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen b_name: 'component-a', a_type: 'library', b_type: 'library', - a_purl: 'pkg:npm/component-a@1.0.0', - b_purl: 'pkg:npm/component-a@1.0.0', + a_purl: purl_a, + b_purl: purl_a, a_version: nil, b_version: '1.0.0', expected: -1 |