diff options
Diffstat (limited to 'spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb')
-rw-r--r-- | spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb new file mode 100644 index 00000000000..c54a3268bbe --- /dev/null +++ b/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Gitlab::Ci::Parsers::Sbom::Validators::CyclonedxSchemaValidator do + # Reports should be valid or invalid according to the specification at + # https://cyclonedx.org/docs/1.4/json/ + + subject(:validator) { described_class.new(report_data) } + + let_it_be(:required_attributes) do + { + "bomFormat" => "CycloneDX", + "specVersion" => "1.4", + "version" => 1 + } + end + + context "with minimally valid report" do + let_it_be(:report_data) { required_attributes } + + it { is_expected.to be_valid } + end + + context "when report has components" do + let(:report_data) { required_attributes.merge({ "components" => components }) } + + context "with minimally valid components" do + let(:components) do + [ + { + "type" => "library", + "name" => "activesupport" + }, + { + "type" => "library", + "name" => "byebug" + } + ] + end + + it { is_expected.to be_valid } + end + + context "when components have versions" do + let(:components) do + [ + { + "type" => "library", + "name" => "activesupport", + "version" => "5.1.4" + }, + { + "type" => "library", + "name" => "byebug", + "version" => "10.0.0" + } + ] + end + + it { is_expected.to be_valid } + end + + context "when components are not valid" do + let(:components) do + [ + { "type" => "foo" }, + { "name" => "activesupport" } + ] + end + + it { is_expected.not_to be_valid } + + it "outputs errors for each validation failure" do + expect(validator.errors).to match_array([ + "property '/components/0' is missing required keys: name", + "property '/components/0/type' is not one of: [\"application\", \"framework\"," \ + " \"library\", \"container\", \"operating-system\", \"device\", \"firmware\", \"file\"]", + "property '/components/1' is missing required keys: type" + ]) + end + end + end + + context "when report has metadata" do + let(:metadata) do + { + "timestamp" => "2022-02-23T08:02:39Z", + "tools" => [{ "vendor" => "GitLab", "name" => "Gemnasium", "version" => "2.34.0" }], + "authors" => [{ "name" => "GitLab", "email" => "support@gitlab.com" }] + } + end + + let(:report_data) { required_attributes.merge({ "metadata" => metadata }) } + + it { is_expected.to be_valid } + + context "when metadata has properties" do + before do + metadata.merge!({ "properties" => properties }) + end + + context "when properties are valid" do + let(:properties) do + [ + { "name" => "gitlab:dependency_scanning:input_file", "value" => "Gemfile.lock" }, + { "name" => "gitlab:dependency_scanning:package_manager", "value" => "bundler" } + ] + end + + it { is_expected.to be_valid } + end + + context "when properties are invalid" do + let(:properties) do + [ + { "name" => ["gitlab:meta:schema_version"], "value" => 1 } + ] + end + + it { is_expected.not_to be_valid } + + it "outputs errors for each validation failure" do + expect(validator.errors).to match_array([ + "property '/metadata/properties/0/name' is not of type: string", + "property '/metadata/properties/0/value' is not of type: string" + ]) + end + end + end + end +end |