From 422e0322b0dcd3fad0c0d03d92c9572e94f007e9 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 12:41:22 -0400 Subject: [PATCH 01/29] Ignores lock file Signed-off-by: M. Scott Ford --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 723ef36..2f6d24c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +Gemfile.lock From 66991c5ed26ed5fba6056e631fae16c8cb6aa346 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 12:54:50 -0400 Subject: [PATCH 02/29] Rename `bin` directory to `exe` This better conforms to the structure that's generated by running the `bundle gem` command. Signed-off-by: M. Scott Ford --- {bin => exe}/cyclonedx-ruby | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {bin => exe}/cyclonedx-ruby (100%) diff --git a/bin/cyclonedx-ruby b/exe/cyclonedx-ruby similarity index 100% rename from bin/cyclonedx-ruby rename to exe/cyclonedx-ruby From 0d0cb40a06a9fbbb4a760813d83b38550f98dfcb Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 12:56:22 -0400 Subject: [PATCH 03/29] Uses git to determine files, excludes tests, and correctly sets the `bindir` This better conforms to the structure that's generated when `bundle gem` is run. Signed-off-by: M. Scott Ford --- cyclonedx-ruby.gemspec | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index 50bc271..4c03bbd 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -8,10 +8,18 @@ Gem::Specification.new do |spec| spec.description = 'CycloneDX is a lightweight software bill-of-material (SBOM) specification designed for use in application security contexts and supply chain component analysis. This Gem generates CycloneDX BOMs from Ruby projects.' spec.authors = ['Joseph Kobti', 'Steve Springett'] spec.email = 'josephkobti@outlook.com' - spec.files = ['lib/bom_builder.rb', 'lib/bom_helpers.rb', 'lib/licenses.json', 'lib/bom_component.rb'] spec.homepage = 'https://github.com/CycloneDX/cyclonedx-ruby-gem' spec.license = 'Apache-2.0' - spec.executables << 'cyclonedx-ruby' + + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor]) + end + end + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ['lib'] + spec.add_dependency('json', '~> 2.2') spec.add_dependency('nokogiri', '~> 1.8') spec.add_dependency('ostruct', '~> 0.1') From 6406c7f404f24ee2f05c07cfcef49d4aab67b21d Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 12:57:15 -0400 Subject: [PATCH 04/29] Adds `cucumber` and `aruba` for writing tests against the executable Signed-off-by: M. Scott Ford --- cyclonedx-ruby.gemspec | 2 ++ features/step_definitions/.gitkeep | 0 features/support/env.rb | 1 + 3 files changed, 3 insertions(+) create mode 100644 features/step_definitions/.gitkeep create mode 100644 features/support/env.rb diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index 4c03bbd..e0c6470 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -26,4 +26,6 @@ Gem::Specification.new do |spec| spec.add_dependency('rest-client', '~> 2.0') spec.add_development_dependency 'rake', '~> 12' spec.add_development_dependency 'rspec', '~> 3.7' + spec.add_development_dependency 'cucumber', '~> 8.0' + spec.add_development_dependency 'aruba', '~> 2.1' end diff --git a/features/step_definitions/.gitkeep b/features/step_definitions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/features/support/env.rb b/features/support/env.rb new file mode 100644 index 0000000..fb0a661 --- /dev/null +++ b/features/support/env.rb @@ -0,0 +1 @@ +require 'aruba/cucumber' From 0b6a0b7a4f4c26222da52077904c33d30ca3b359 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 13:05:24 -0400 Subject: [PATCH 05/29] Adds missing dependency for `activesupport` `bom_builder.rb` is requiring `active_support/core_ext/hash` but `activesupport` wasn't listed in the `.gemspec` as a dependency. This likely hasn't come up before because consumers have had `activesupport` listed as dependency. Signed-off-by: M. Scott Ford --- cyclonedx-ruby.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index e0c6470..e5973aa 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -24,6 +24,7 @@ Gem::Specification.new do |spec| spec.add_dependency('nokogiri', '~> 1.8') spec.add_dependency('ostruct', '~> 0.1') spec.add_dependency('rest-client', '~> 2.0') + spec.add_dependency('activesupport', '~> 7.0') spec.add_development_dependency 'rake', '~> 12' spec.add_development_dependency 'rspec', '~> 3.7' spec.add_development_dependency 'cucumber', '~> 8.0' From 6a41f8e684a5b0860b9ff7a5adf857b7a485c01c Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 13:10:23 -0400 Subject: [PATCH 06/29] Adds coverage for the `--help` parameter Signed-off-by: M. Scott Ford --- features/help.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 features/help.feature diff --git a/features/help.feature b/features/help.feature new file mode 100644 index 0000000..a0f9231 --- /dev/null +++ b/features/help.feature @@ -0,0 +1,28 @@ +Feature: Command Help + +The `cyclonedx-ruby` needs to provide help output so that people know the +parameters that they can specify. + +Scenario: Responding to `--help` + Given I run `cyclonedx-ruby --help` + Then the output should contain: + """ + Usage: cyclonedx-ruby [options] + -v, --[no-]verbose Run verbosely + -p, --path path (Required) Path to Ruby project directory + -o, --output bom_file_path (Optional) Path to output the bom.xml file to + -f, --format bom_output_format (Optional) Output format for bom. Currently support xml (default) and json. + -h, --help Show help message + """ + +Scenario: Responding to `-h` + Given I run `cyclonedx-ruby --help` + Then the output should contain: + """ + Usage: cyclonedx-ruby [options] + -v, --[no-]verbose Run verbosely + -p, --path path (Required) Path to Ruby project directory + -o, --output bom_file_path (Optional) Path to output the bom.xml file to + -f, --format bom_output_format (Optional) Output format for bom. Currently support xml (default) and json. + -h, --help Show help message + """ From c5008cbefc750c21ff2b6316fb6b1b8b623b92e3 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 13:17:03 -0400 Subject: [PATCH 07/29] Only ignores `Gemfile.lock` when it appears in the root This avoids issues with `Gemfile.lock` files being used with fixtures. Signed-off-by: M. Scott Ford --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2f6d24c..519a043 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .idea -Gemfile.lock +/Gemfile.lock From d8a609eb54f700d75e3ca24c469e002217fb3c0e Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 13:17:47 -0400 Subject: [PATCH 08/29] Adds a simple fixture to assist with testing This `Gemfile` and `Gemfile.lock` only references `activesupport`. Signed-off-by: M. Scott Ford --- features/fixtures/simple/Gemfile | 3 +++ features/fixtures/simple/Gemfile.lock | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 features/fixtures/simple/Gemfile create mode 100644 features/fixtures/simple/Gemfile.lock diff --git a/features/fixtures/simple/Gemfile b/features/fixtures/simple/Gemfile new file mode 100644 index 0000000..180e0f6 --- /dev/null +++ b/features/fixtures/simple/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'activesupport' diff --git a/features/fixtures/simple/Gemfile.lock b/features/fixtures/simple/Gemfile.lock new file mode 100644 index 0000000..db602fc --- /dev/null +++ b/features/fixtures/simple/Gemfile.lock @@ -0,0 +1,23 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.0.4.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + concurrent-ruby (1.2.2) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + minitest (5.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + +PLATFORMS + arm64-darwin-22 + +DEPENDENCIES + activesupport + +BUNDLED WITH + 2.4.10 From 9af170e0dcb7997d7c7ebe26f75904f36aaa7c69 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:46:15 -0400 Subject: [PATCH 09/29] Silences cucumber publish message Signed-off-by: M. Scott Ford --- cucumber.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 cucumber.yml diff --git a/cucumber.yml b/cucumber.yml new file mode 100644 index 0000000..fea5edc --- /dev/null +++ b/cucumber.yml @@ -0,0 +1 @@ +default: --publish-quiet From 1ed551056c02c1a69613710d5c246ddbd344fde7 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:46:30 -0400 Subject: [PATCH 10/29] Adds expected xml bom to fixture Signed-off-by: M. Scott Ford --- features/fixtures/simple/bom.xml.expected | 75 +++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 features/fixtures/simple/bom.xml.expected diff --git a/features/fixtures/simple/bom.xml.expected b/features/fixtures/simple/bom.xml.expected new file mode 100644 index 0000000..b379102 --- /dev/null +++ b/features/fixtures/simple/bom.xml.expected @@ -0,0 +1,75 @@ + + + + + activesupport + 7.0.4.3 + A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. + + 571ed0fac8510f1fc8a1d66aa070d07ea269913bf9ef50960a8044536358a096 + + + + MIT + + + pkg:gem/activesupport@7.0.4.3 + + + concurrent-ruby + 1.2.2 + Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns. + + 3879119b8b75e3b62616acc256c64a134d0b0a7a9a3fcba5a233025bcde22c4f + + + + MIT + + + pkg:gem/concurrent-ruby@1.2.2 + + + i18n + 1.12.0 + New wave Internationalization support for Ruby + + 91e3cc1b97616d308707eedee413d82ee021d751c918661fb82152793e64aced + + + + MIT + + + pkg:gem/i18n@1.12.0 + + + minitest + 5.18.0 + minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking + + 06f43aa0692ce3acf19cb5bc539ad2c6095ca3d2c7e5fbafc58a7d847e898745 + + + + MIT + + + pkg:gem/minitest@5.18.0 + + + tzinfo + 2.0.6 + Time Zone Library + + 8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b + + + + MIT + + + pkg:gem/tzinfo@2.0.6 + + + From 4836115c337da73e6a71a5be209738c22057f6dc Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:46:57 -0400 Subject: [PATCH 11/29] Adds coverage for using `--path` with default options Signed-off-by: M. Scott Ford --- features/defaults.feature | 13 +++++++++++++ features/step_definitions/xml_bom_matching.rb | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 features/defaults.feature create mode 100644 features/step_definitions/xml_bom_matching.rb diff --git a/features/defaults.feature b/features/defaults.feature new file mode 100644 index 0000000..3157633 --- /dev/null +++ b/features/defaults.feature @@ -0,0 +1,13 @@ +Feature: Default parameter values + +Many of the options for the `cyclonedx-ruby` command are optional. + +Scenario: Running against simple fixture + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path .` + Then the output should contain: + """ + 5 gems were written to BOM located at ./bom.xml + """ + And a file named "bom.xml" should exist + And the generated XML BOM file "bom.xml" matches "bom.xml.expected" diff --git a/features/step_definitions/xml_bom_matching.rb b/features/step_definitions/xml_bom_matching.rb new file mode 100644 index 0000000..a142512 --- /dev/null +++ b/features/step_definitions/xml_bom_matching.rb @@ -0,0 +1,11 @@ +Then('the generated XML BOM file {string} matches {string}') do |generated_file, expected_file| + generated_file_contents = File.read(expand_path(generated_file)) + expected_file_contents = File.read(expand_path(expected_file)) + + serial_number_matcher = /serialNumber=\"urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"/ + normalized_serial_number = 'serialNumber="00000000-0000-0000-0000-000000000000"' + normalized_generated_file_contents = generated_file_contents.gsub(serial_number_matcher, normalized_serial_number) + normalized_expected_file_contents = expected_file_contents.gsub(serial_number_matcher, normalized_serial_number) + + expect(normalized_expected_file_contents).to eq(normalized_generated_file_contents) +end From 70b538257b999a0995ce874ba0d7b7d83279979c Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:51:26 -0400 Subject: [PATCH 12/29] Removes `-h` scenario I'm not sure that acceptance tests for the short parameters makes sense. I think a unit test would be a better way to go about handling that. Signed-off-by: M. Scott Ford --- features/help.feature | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/features/help.feature b/features/help.feature index a0f9231..f2ee863 100644 --- a/features/help.feature +++ b/features/help.feature @@ -3,19 +3,7 @@ Feature: Command Help The `cyclonedx-ruby` needs to provide help output so that people know the parameters that they can specify. -Scenario: Responding to `--help` - Given I run `cyclonedx-ruby --help` - Then the output should contain: - """ - Usage: cyclonedx-ruby [options] - -v, --[no-]verbose Run verbosely - -p, --path path (Required) Path to Ruby project directory - -o, --output bom_file_path (Optional) Path to output the bom.xml file to - -f, --format bom_output_format (Optional) Output format for bom. Currently support xml (default) and json. - -h, --help Show help message - """ - -Scenario: Responding to `-h` +Scenario: Generate help on demand Given I run `cyclonedx-ruby --help` Then the output should contain: """ From 22a500b73514c033766c2365eb1757c62bb6049a Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:52:03 -0400 Subject: [PATCH 13/29] Ignores temp location used by `aruba` Signed-off-by: M. Scott Ford --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 519a043..da60a6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea /Gemfile.lock +/tmp/aruba From baf50d99255389fb6b59f57de150ae79d9f55032 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:52:16 -0400 Subject: [PATCH 14/29] Adds feature for specifying `--format xml` Signed-off-by: M. Scott Ford --- features/xml_format.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 features/xml_format.feature diff --git a/features/xml_format.feature b/features/xml_format.feature new file mode 100644 index 0000000..69c05f9 --- /dev/null +++ b/features/xml_format.feature @@ -0,0 +1,11 @@ +Feature: Creating BOM using XML format + + Scenario: Running against simple fixture + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format xml` + Then the output should contain: + """ + 5 gems were written to BOM located at ./bom.xml + """ + And a file named "bom.xml" should exist + And the generated XML BOM file "bom.xml" matches "bom.xml.expected" From d5b770b36f0426c2a53216b60229da6a8a150150 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:57:57 -0400 Subject: [PATCH 15/29] Correctly formats `serialNumber` after replacement Signed-off-by: M. Scott Ford --- features/step_definitions/xml_bom_matching.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/step_definitions/xml_bom_matching.rb b/features/step_definitions/xml_bom_matching.rb index a142512..004c9b2 100644 --- a/features/step_definitions/xml_bom_matching.rb +++ b/features/step_definitions/xml_bom_matching.rb @@ -3,7 +3,7 @@ expected_file_contents = File.read(expand_path(expected_file)) serial_number_matcher = /serialNumber=\"urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"/ - normalized_serial_number = 'serialNumber="00000000-0000-0000-0000-000000000000"' + normalized_serial_number = 'serialNumber="urn:uuid:00000000-0000-0000-0000-000000000000"' normalized_generated_file_contents = generated_file_contents.gsub(serial_number_matcher, normalized_serial_number) normalized_expected_file_contents = expected_file_contents.gsub(serial_number_matcher, normalized_serial_number) From a4703d7244eb38b834a0b8a6922994b4011e2a29 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:58:15 -0400 Subject: [PATCH 16/29] Adds expected Json BOM to fixture Signed-off-by: M. Scott Ford --- features/fixtures/simple/bom.json.expected | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 features/fixtures/simple/bom.json.expected diff --git a/features/fixtures/simple/bom.json.expected b/features/fixtures/simple/bom.json.expected new file mode 100644 index 0000000..d9d7dce --- /dev/null +++ b/features/fixtures/simple/bom.json.expected @@ -0,0 +1,108 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.1", + "serialNumber": "urn:uuid:d498cdc2-5494-4031-b37d-ff3d10d336bf", + "version": 1, + "components": [ + { + "type": "library", + "name": "activesupport", + "version": "7.0.4.3", + "description": "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.", + "purl": "pkg:gem/activesupport@7.0.4.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "571ed0fac8510f1fc8a1d66aa070d07ea269913bf9ef50960a8044536358a096" + } + ], + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ] + }, + { + "type": "library", + "name": "concurrent-ruby", + "version": "1.2.2", + "description": "Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.", + "purl": "pkg:gem/concurrent-ruby@1.2.2", + "hashes": [ + { + "alg": "SHA-256", + "content": "3879119b8b75e3b62616acc256c64a134d0b0a7a9a3fcba5a233025bcde22c4f" + } + ], + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ] + }, + { + "type": "library", + "name": "i18n", + "version": "1.12.0", + "description": "New wave Internationalization support for Ruby", + "purl": "pkg:gem/i18n@1.12.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "91e3cc1b97616d308707eedee413d82ee021d751c918661fb82152793e64aced" + } + ], + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ] + }, + { + "type": "library", + "name": "minitest", + "version": "5.18.0", + "description": "minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking", + "purl": "pkg:gem/minitest@5.18.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "06f43aa0692ce3acf19cb5bc539ad2c6095ca3d2c7e5fbafc58a7d847e898745" + } + ], + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ] + }, + { + "type": "library", + "name": "tzinfo", + "version": "2.0.6", + "description": "Time Zone Library", + "purl": "pkg:gem/tzinfo@2.0.6", + "hashes": [ + { + "alg": "SHA-256", + "content": "8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b" + } + ], + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ] + } + ] +} \ No newline at end of file From 207dd442635e052c1e86cae36bd3baa8462e7e61 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 14:58:26 -0400 Subject: [PATCH 17/29] Adds feature for Json format Signed-off-by: M. Scott Ford --- features/json_format.feature | 11 +++++++++++ features/step_definitions/json_bom_matching.rb | 12 ++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 features/json_format.feature create mode 100644 features/step_definitions/json_bom_matching.rb diff --git a/features/json_format.feature b/features/json_format.feature new file mode 100644 index 0000000..13a2cb3 --- /dev/null +++ b/features/json_format.feature @@ -0,0 +1,11 @@ +Feature: Creating BOM using Json format + + Scenario: Running against simple fixture + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format json` + Then the output should contain: + """ + 5 gems were written to BOM located at ./bom.json + """ + And a file named "bom.json" should exist + And the generated XML Json file "bom.json" matches "bom.json.expected" diff --git a/features/step_definitions/json_bom_matching.rb b/features/step_definitions/json_bom_matching.rb new file mode 100644 index 0000000..33a6c49 --- /dev/null +++ b/features/step_definitions/json_bom_matching.rb @@ -0,0 +1,12 @@ +Then('the generated XML Json file {string} matches {string}') do |generated_file, expected_file| + generated_file_contents = File.read(expand_path(generated_file)) + expected_file_contents = File.read(expand_path(expected_file)) + + # "serialNumber": "urn:uuid:d498cdc2-5494-4031-b37d-ff3d10d336bf" + serial_number_matcher = /\"serialNumber\": \"urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"/ + normalized_serial_number = '"serialNumber": "urn:uuid:00000000-0000-0000-0000-000000000000"' + normalized_generated_file_contents = generated_file_contents.gsub(serial_number_matcher, normalized_serial_number) + normalized_expected_file_contents = expected_file_contents.gsub(serial_number_matcher, normalized_serial_number) + + expect(normalized_expected_file_contents).to eq(normalized_generated_file_contents) +end From 313ef44aabf73360f999111187e19c58e6d5b782 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Sun, 2 Apr 2023 15:07:40 -0400 Subject: [PATCH 18/29] Adds coverage for specifying the output path Signed-off-by: M. Scott Ford --- features/json_format.feature | 12 +++++++++++- features/xml_format.feature | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/features/json_format.feature b/features/json_format.feature index 13a2cb3..5bcde09 100644 --- a/features/json_format.feature +++ b/features/json_format.feature @@ -1,6 +1,6 @@ Feature: Creating BOM using Json format - Scenario: Running against simple fixture + Scenario: Using default output path Given I use a fixture named "simple" And I run `cyclonedx-ruby --path . --format json` Then the output should contain: @@ -9,3 +9,13 @@ Feature: Creating BOM using Json format """ And a file named "bom.json" should exist And the generated XML Json file "bom.json" matches "bom.json.expected" + + Scenario: Specifying the output path + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format json --output bom/simple.bom.json` + Then the output should contain: + """ + 5 gems were written to BOM located at bom/simple.bom.json + """ + And a file named "bom/simple.bom.json" should exist + And the generated XML Json file "bom/simple.bom.json" matches "bom.json.expected" diff --git a/features/xml_format.feature b/features/xml_format.feature index 69c05f9..37fa650 100644 --- a/features/xml_format.feature +++ b/features/xml_format.feature @@ -1,6 +1,6 @@ Feature: Creating BOM using XML format - Scenario: Running against simple fixture + Scenario: Using default output path Given I use a fixture named "simple" And I run `cyclonedx-ruby --path . --format xml` Then the output should contain: @@ -9,3 +9,13 @@ Feature: Creating BOM using XML format """ And a file named "bom.xml" should exist And the generated XML BOM file "bom.xml" matches "bom.xml.expected" + + Scenario: Specifying the output path + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format xml --output bom/simple.bom.xml` + Then the output should contain: + """ + 5 gems were written to BOM located at bom/simple.bom.xml + """ + And a file named "bom/simple.bom.xml" should exist + And the generated XML BOM file "bom/simple.bom.xml" matches "bom.xml.expected" From 617f1bdd3fd89c0e2ca78dabed9be71d7b3570cd Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 17:08:15 -0400 Subject: [PATCH 19/29] Adds `simplecov` and configures it to collect coverage from `cucumber` Signed-off-by: M. Scott Ford --- .gitignore | 1 + .simplecov | 38 +++++++++++++++++++++++++++ Rakefile | 19 ++++++++++++-- cyclonedx-ruby.gemspec | 1 + features/support/env.rb | 32 ++++++++++++++++++++++ features/support/simplecov_support.rb | 15 +++++++++++ 6 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 .simplecov create mode 100644 features/support/simplecov_support.rb diff --git a/.gitignore b/.gitignore index da60a6e..29a7627 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea /Gemfile.lock /tmp/aruba +/coverage \ No newline at end of file diff --git a/.simplecov b/.simplecov new file mode 100644 index 0000000..f1709c5 --- /dev/null +++ b/.simplecov @@ -0,0 +1,38 @@ +# Copied from https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/.simplecov +# Licensed under MIT - https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/LICENSE + +SimpleCov.configure do + enable_for_subprocesses true + + # Activate branch coverage + enable_coverage :branch + + # ignore this file + add_filter ".simplecov" + add_filter "features" + + # Rake tasks aren't tested with rspec + add_filter "Rakefile" + add_filter "lib/tasks" + + # + # Changed Files in Git Group + # @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only + untracked = `git ls-files --exclude-standard --others` + unstaged = `git diff --name-only` + staged = `git diff --name-only --cached` + all = untracked + unstaged + staged + changed_filenames = all.split("\n") + + add_group "Changed" do |source_file| + changed_filenames.select do |changed_filename| + source_file.filename.end_with?(changed_filename) + end + end + + add_group "Libraries", "lib" + + # Specs are reported on to ensure that all examples are being run and all + # lets, befores, afters, etc are being used. + add_group "Specs", "spec/" +end diff --git a/Rakefile b/Rakefile index 5c4b046..47e60f8 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,22 @@ #!/usr/bin/env rake +$LOAD_PATH << File.expand_path(__dir__) + +require "aruba/platform" + +require "bundler" +Bundler.setup + require 'bundler/gem_tasks' -require 'rspec/core/rake_task' +require "cucumber/rake/task" +require "rspec/core/rake_task" + +Cucumber::Rake::Task.new do |t| + t.cucumber_opts = %w(--format progress) +end RSpec::Core::RakeTask.new('spec') -task default: :spec \ No newline at end of file +desc "Run the whole test suite." +task test: [:spec, :cucumber] + +task default: :test \ No newline at end of file diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index e5973aa..15a16e2 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -29,4 +29,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rspec', '~> 3.7' spec.add_development_dependency 'cucumber', '~> 8.0' spec.add_development_dependency 'aruba', '~> 2.1' + spec.add_development_dependency 'simplecov', '~> 0.22.0' end diff --git a/features/support/env.rb b/features/support/env.rb index fb0a661..331ff6a 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1 +1,33 @@ +# Based on https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/features/support/env.rb +# Licensed under MIT - https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/LICENSE + +$LOAD_PATH.unshift File.expand_path('../../lib', __dir__) + +# Has to be the first file required so that all other files show coverage information +require_relative 'simplecov_support' unless RUBY_PLATFORM.include?('java') + +require 'fileutils' +require 'pathname' + require 'aruba/cucumber' +require 'rspec/expectations' + +Around do |test_case, block| + command_name = "#{test_case.location.file}:#{test_case.location.line} # #{test_case.name}" + + # Used in simplecov_setup so that each scenario has a different name and + # their coverage results are merged instead of overwriting each other as + # 'Cucumber Features' + set_environment_variable 'SIMPLECOV_COMMAND_NAME', command_name.to_s + + simplecov_setup_pathname = + Pathname.new(__FILE__).expand_path.parent.to_s + + # set environment variable so child processes will merge their coverage data + # with parent process's coverage data. + prepend_environment_variable 'RUBYOPT', "-I#{simplecov_setup_pathname} -rsimplecov_support " + + with_environment do + block.call + end +end diff --git a/features/support/simplecov_support.rb b/features/support/simplecov_support.rb new file mode 100644 index 0000000..b3a91a3 --- /dev/null +++ b/features/support/simplecov_support.rb @@ -0,0 +1,15 @@ +# Copied from https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/features/support/simplecov_setup.rb +# Licensed under MIT - https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/LICENSE + +# @note this file is loaded in env.rb to setup simplecov using RUBYOPTs for +# child processes and @in-process +unless RUBY_PLATFORM.include?('java') + require 'simplecov' + root = File.expand_path('../..', __dir__) + command_name = ENV['SIMPLECOV_COMMAND_NAME'] || 'Cucumber Features' + SimpleCov.command_name(command_name) + SimpleCov.root(root) + + # Run simplecov by default + SimpleCov.start unless ENV.key? 'ARUBA_NO_COVERAGE' +end From eaf308c04b8dd5c84d827454c35c46ca89f79e60 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 17:09:11 -0400 Subject: [PATCH 20/29] Adds a test for the `purl` helper method This was mainly done to make sure the `simplecov` configuration was working correctly. Signed-off-by: M. Scott Ford --- spec/bom_helpers_spec.rb | 10 ++++++++++ spec/spec_helper.rb | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 spec/bom_helpers_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/spec/bom_helpers_spec.rb b/spec/bom_helpers_spec.rb new file mode 100644 index 0000000..75adec2 --- /dev/null +++ b/spec/bom_helpers_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' +require 'bom_helpers' + +RSpec.describe 'helper methods' do + context '#purl' do + it 'builds a purl' do + expect(purl('activesupport', '7.0.1')).to eq("pkg:gem/activesupport@7.0.1") + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..24b4245 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,16 @@ +# Copied from https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/spec/spec_helper.rb +# Licensed under MIT - https://github.com/cucumber/aruba/blob/3b1a6cea6e3ba55370c3396eef0a955aeb40f287/LICENSE + +$LOAD_PATH << File.expand_path('../lib', __dir__) + +unless RUBY_PLATFORM.include?('java') + require 'simplecov' + SimpleCov.command_name 'RSpec' + + # Run simplecov by default + SimpleCov.start unless ENV.key? 'ARUBA_NO_COVERAGE' +end + +# Loading support files +Dir.glob(File.expand_path('support/*.rb', __dir__)).sort.each { |f| require_relative f } +Dir.glob(File.expand_path('support/**/*.rb', __dir__)).sort.each { |f| require_relative f } From b4365fbc18d53890e623d74dd2843e48b47ce6a5 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 21:14:01 -0400 Subject: [PATCH 21/29] Ensure that `coverage` dir is removed before running test suite Signed-off-by: M. Scott Ford --- Rakefile | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 47e60f8..a18e7a9 100644 --- a/Rakefile +++ b/Rakefile @@ -9,6 +9,28 @@ Bundler.setup require 'bundler/gem_tasks' require "cucumber/rake/task" require "rspec/core/rake_task" +require 'rake/clean' + +# Work around a bug in `rake/clean` from `rake` versions older than 13. It's +# failing when it calls `FileUtils::rm_r` because that method needs to receive +# the `opts` parameter as parameters instead of as a `Hash`. +module Rake + module Cleaner + module_function + + def cleanup(file_name, **opts) + begin + opts = { verbose: Rake.application.options.trace }.merge(opts) + rm_r file_name, **opts + rescue StandardError => ex + puts "Failed to remove #{file_name}: #{ex}" unless file_already_gone?(file_name) + end + end + end +end + +# Remove the `coverage` directory when the `:clobber` task is run. +CLOBBER.include('coverage') Cucumber::Rake::Task.new do |t| t.cucumber_opts = %w(--format progress) @@ -16,7 +38,10 @@ end RSpec::Core::RakeTask.new('spec') +# Run the `clobber` task when running the entire test suite, because the +# coverage information reported by `simplecov` can be skewed when a `coverage` +# directory is already present. desc "Run the whole test suite." -task test: [:spec, :cucumber] +task test: [:clobber, :spec, :cucumber] task default: :test \ No newline at end of file From 9b23376e12a96a69119f4570552aa219d49ca649 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 21:28:56 -0400 Subject: [PATCH 22/29] Adds coverage for `--verbose` Signed-off-by: M. Scott Ford --- features/json_format.feature | 22 ++++++++++++++++++++++ features/xml_format.feature | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/features/json_format.feature b/features/json_format.feature index 5bcde09..eed82b7 100644 --- a/features/json_format.feature +++ b/features/json_format.feature @@ -19,3 +19,25 @@ Feature: Creating BOM using Json format """ And a file named "bom/simple.bom.json" should exist And the generated XML Json file "bom/simple.bom.json" matches "bom.json.expected" + + Scenario: Verbose output + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format json --verbose` + Then the output should match: + """ + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Changing directory to Ruby project directory located at \. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : BOM will be written to \./bom\.json + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Parsing specs from \./Gemfile\.lock\.\.\. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Specs successfully parsed! + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : activesupport:7\.0\.4\.3 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : concurrent-ruby:1\.2\.2 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : i18n:1\.12\.0 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : minitest:5\.18\.0 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : tzinfo:2\.0\.6 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Changing directory to the original working directory located at .*/tmp/aruba/simple + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Writing BOM to \./bom\.json\.\.\. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : 5 gems were written to BOM located at \./bom\.json + """ + And a file named "bom.json" should exist + And the generated XML Json file "bom.json" matches "bom.json.expected" + diff --git a/features/xml_format.feature b/features/xml_format.feature index 37fa650..2c66880 100644 --- a/features/xml_format.feature +++ b/features/xml_format.feature @@ -19,3 +19,24 @@ Feature: Creating BOM using XML format """ And a file named "bom/simple.bom.xml" should exist And the generated XML BOM file "bom/simple.bom.xml" matches "bom.xml.expected" + + Scenario: Verbose output + Given I use a fixture named "simple" + And I run `cyclonedx-ruby --path . --format xml --verbose` + Then the output should match: + """ + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Changing directory to Ruby project directory located at \. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : BOM will be written to \./bom\.xml + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Parsing specs from \./Gemfile\.lock\.\.\. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Specs successfully parsed! + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : activesupport:7\.0\.4\.3 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : concurrent-ruby:1\.2\.2 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : i18n:1\.12\.0 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : minitest:5\.18\.0 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : tzinfo:2\.0\.6 gem added + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Changing directory to the original working directory located at .*/tmp/aruba/simple + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : Writing BOM to \./bom\.xml\.\.\. + I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : 5 gems were written to BOM located at \./bom\.xml + """ + And a file named "bom.xml" should exist + And the generated XML BOM file "bom.xml" matches "bom.xml.expected" From 1fae41bae05444b9ffe8904ca3819f459a6fcaa0 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 21:30:26 -0400 Subject: [PATCH 23/29] Fixes typo in Json comparison step Signed-off-by: M. Scott Ford --- features/json_format.feature | 6 +++--- features/step_definitions/json_bom_matching.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/json_format.feature b/features/json_format.feature index eed82b7..ae231fb 100644 --- a/features/json_format.feature +++ b/features/json_format.feature @@ -8,7 +8,7 @@ Feature: Creating BOM using Json format 5 gems were written to BOM located at ./bom.json """ And a file named "bom.json" should exist - And the generated XML Json file "bom.json" matches "bom.json.expected" + And the generated Json BOM file "bom.json" matches "bom.json.expected" Scenario: Specifying the output path Given I use a fixture named "simple" @@ -18,7 +18,7 @@ Feature: Creating BOM using Json format 5 gems were written to BOM located at bom/simple.bom.json """ And a file named "bom/simple.bom.json" should exist - And the generated XML Json file "bom/simple.bom.json" matches "bom.json.expected" + And the generated Json BOM file "bom/simple.bom.json" matches "bom.json.expected" Scenario: Verbose output Given I use a fixture named "simple" @@ -39,5 +39,5 @@ Feature: Creating BOM using Json format I, \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6} #\d+\] INFO -- : 5 gems were written to BOM located at \./bom\.json """ And a file named "bom.json" should exist - And the generated XML Json file "bom.json" matches "bom.json.expected" + And the generated Json BOM file "bom.json" matches "bom.json.expected" diff --git a/features/step_definitions/json_bom_matching.rb b/features/step_definitions/json_bom_matching.rb index 33a6c49..83ee847 100644 --- a/features/step_definitions/json_bom_matching.rb +++ b/features/step_definitions/json_bom_matching.rb @@ -1,4 +1,4 @@ -Then('the generated XML Json file {string} matches {string}') do |generated_file, expected_file| +Then('the generated Json BOM file {string} matches {string}') do |generated_file, expected_file| generated_file_contents = File.read(expand_path(generated_file)) expected_file_contents = File.read(expand_path(expected_file)) From aae1fecef08624ee52be49503ce402c8d3fbfa7e Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Mon, 3 Apr 2023 22:34:39 -0400 Subject: [PATCH 24/29] Increases coverage for `BomComponent` class Signed-off-by: M. Scott Ford --- spec/bom_component_spec.rb | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 spec/bom_component_spec.rb diff --git a/spec/bom_component_spec.rb b/spec/bom_component_spec.rb new file mode 100644 index 0000000..e02f4d5 --- /dev/null +++ b/spec/bom_component_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' +require 'bom_component' + +RSpec.shared_examples "a valid hash_val result for gem" do + it { expect(result.count).to eq(1) } + it { expect(result[0][:type]).to eq('library') } + it { expect(result[0][:name]).to eq(gem.name) } + it { expect(result[0][:version]).to eq(gem.version) } + it { expect(result[0][:description]).to eq(gem.description) } + it { expect(result[0][:purl]).to eq(gem.purl) } + it { expect(result[0][:hashes].count).to eq(1) } + it { expect(result[0][:hashes][0][:alg]).to eq('SHA-256') } + it { expect(result[0][:hashes][0][:content]).to eq(gem.hash) } +end + +RSpec.describe BomComponent do + context '#hash_val' do + let(:base_gem) do + OpenStruct.new( + name: 'Sample', + version: '1.0.0', + description: 'Sample description', + hash: '1f809ab336c437d894df9934a9fc9ffd2ea09b535dfa4e3f75db078531c260c8', + purl: 'pkg:gem/sample@1.0.0' + ) + end + + let(:gem) do + base_gem + end + + subject(:result) { BomComponent.new(gem).hash_val } + + context 'with a gem without a license' do + include_examples 'a valid hash_val result for gem' + end + + context 'with a gem that has a license_id' do + let(:gem) do + base_gem.tap do |value| + value.license_id = 'License ID' + end + end + + include_examples 'a valid hash_val result for gem' + + it { expect(result[0][:licenses].count).to eq(1) } + it { expect(result[0][:licenses][0][:license][:id]).to eq(gem.license_id) } + end + + context 'with a gem that has a license_name' do + let(:gem) do + base_gem.tap do |value| + value.license_name = 'License Name' + end + end + + include_examples 'a valid hash_val result for gem' + + it { expect(result[0][:licenses].count).to eq(1) } + it { expect(result[0][:licenses][0][:license][:name]).to eq(gem.license_name) } + end + end +end From c6f82df57f485a6232e77cf71dc5d1521c522f40 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Wed, 5 Apr 2023 14:36:42 -0400 Subject: [PATCH 25/29] Adds a matrix of ruby versions to run tests against Signed-off-by: M. Scott Ford --- .github/workflows/ruby.yml | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index e10ffe2..d939d1d 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -1,20 +1,31 @@ -name: Ruby CI +name: Ruby -on: [push, pull_request] +on: + push: + branches: + - main + + pull_request: jobs: build: - runs-on: ubuntu-latest + name: Ruby ${{ matrix.ruby }} + strategy: + matrix: + ruby: + - '3.2.2' + - '3.1.4' + - '3.0.6' + - '2.7.7' + - '2.6.6' steps: - uses: actions/checkout@v3 - - name: Set up Ruby 2.6 + - name: Set up Ruby ${{ matrix.ruby }} uses: ruby/setup-ruby@v1 with: - ruby-version: '2.6' - - name: Build and test with Rake - run: | - gem install bundler - bundle install --jobs 4 --retry 3 - bundle exec rake + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run the default task + run: bundle exec rake From 8b4dea77fc83d7fa51e5cd954af9dcacc53dff28 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Wed, 5 Apr 2023 15:34:33 -0400 Subject: [PATCH 26/29] Removes ruby 2.6 `activesupport` version 7.x does not support Ruby versions older than 2.7. Signed-off-by: M. Scott Ford --- .github/workflows/ruby.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index d939d1d..645e586 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -18,7 +18,6 @@ jobs: - '3.1.4' - '3.0.6' - '2.7.7' - - '2.6.6' steps: - uses: actions/checkout@v3 From 50c6953802a946ade81cc2e90978086811faaa00 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Wed, 5 Apr 2023 15:40:18 -0400 Subject: [PATCH 27/29] Specifies the supported ruby version Signed-off-by: M. Scott Ford --- cyclonedx-ruby.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index 15a16e2..23a861c 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -11,6 +11,8 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/CycloneDX/cyclonedx-ruby-gem' spec.license = 'Apache-2.0' + spec.required_ruby_version = ">= 2.7.0" + spec.files = Dir.chdir(__dir__) do `git ls-files -z`.split("\x0").reject do |f| (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor]) From 40a61d93cb11155fc7259ae742f8f1c7dc5047fd Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Wed, 5 Apr 2023 15:44:04 -0400 Subject: [PATCH 28/29] Removes comment that was used during development Signed-off-by: M. Scott Ford --- features/step_definitions/json_bom_matching.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/features/step_definitions/json_bom_matching.rb b/features/step_definitions/json_bom_matching.rb index 83ee847..0a81ea1 100644 --- a/features/step_definitions/json_bom_matching.rb +++ b/features/step_definitions/json_bom_matching.rb @@ -2,7 +2,6 @@ generated_file_contents = File.read(expand_path(generated_file)) expected_file_contents = File.read(expand_path(expected_file)) - # "serialNumber": "urn:uuid:d498cdc2-5494-4031-b37d-ff3d10d336bf" serial_number_matcher = /\"serialNumber\": \"urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"/ normalized_serial_number = '"serialNumber": "urn:uuid:00000000-0000-0000-0000-000000000000"' normalized_generated_file_contents = generated_file_contents.gsub(serial_number_matcher, normalized_serial_number) From f510a03e76e488fc75df2610b989c99cebae67d8 Mon Sep 17 00:00:00 2001 From: "M. Scott Ford" Date: Wed, 5 Apr 2023 16:01:55 -0400 Subject: [PATCH 29/29] Specifies rubocop target version Sonatype Lift is using Rubocop to report quality violations. The default configuration Sonatype Lift is using is not publically available. So in order to fix the comment that it left on the pull request after the version requirement was added to the `.gemspec` file, I added Rubocop as a development dependency, and then generated a TODO style configuration that excludes all of the default warnings except for the one that Sonatype Lift reported. That one was fixed. Signed-off-by: M. Scott Ford --- .rubocop.yml | 17 +++ .rubocop_todo.yml | 290 +++++++++++++++++++++++++++++++++++++++++ cyclonedx-ruby.gemspec | 1 + 3 files changed, 308 insertions(+) create mode 100644 .rubocop.yml create mode 100644 .rubocop_todo.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..0dbd7ac --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,17 @@ +AllCops: + NewCops: enable + TargetRubyVersion: 2.7 + +inherit_from: .rubocop_todo.yml + +# The behavior of RuboCop can be controlled via the .rubocop.yml +# configuration file. It makes it possible to enable/disable +# certain cops (checks) and to alter their behavior if they accept +# any parameters. The file can be placed either in your home +# directory or in some project directory. +# +# RuboCop will start looking for the configuration file in the directory +# where the inspected file is and continue its way up to the root directory. +# +# See https://docs.rubocop.org/rubocop/configuration + diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..accbce0 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,290 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-04-05 19:57:43 UTC using RuboCop version 1.49.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Severity, Include. +# Include: **/*.gemspec +Gemspec/DeprecatedAttributeAssignment: + Exclude: + - 'cyclonedx-ruby.gemspec' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. +# Include: **/*.gemspec +Gemspec/OrderedDependencies: + Exclude: + - 'cyclonedx-ruby.gemspec' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Severity, Include. +# Include: **/*.gemspec +Gemspec/RequireMFA: + Exclude: + - 'cyclonedx-ruby.gemspec' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Layout/EmptyLineAfterMagicComment: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: around, only_before +Layout/EmptyLinesAroundAccessModifier: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Layout/EmptyLinesAroundMethodBody: + Exclude: + - 'lib/bom_component.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment. +Layout/ExtraSpacing: + Exclude: + - 'cyclonedx-ruby.gemspec' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Layout/FirstArrayElementIndentation: + Exclude: + - 'lib/bom_component.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Layout/LeadingEmptyLines: + Exclude: + - 'lib/bom_component.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: final_newline, final_blank_line +Layout/TrailingEmptyLines: + Exclude: + - 'Rakefile' + - 'lib/bom_component.rb' + +# Offense count: 3 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowInHeredoc. +Layout/TrailingWhitespace: + Exclude: + - 'Rakefile' + - 'spec/bom_component_spec.rb' + +# Offense count: 2 +Lint/IneffectiveAccessModifier: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Lint/ScriptPermission: + Exclude: + - 'Rakefile' + +# Offense count: 1 +Lint/ShadowingOuterLocalVariable: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 19 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: strict, consistent +Lint/SymbolConversion: + Exclude: + - 'lib/bom_component.rb' + - 'lib/bom_helpers.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. +Lint/UnusedMethodArgument: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods. +Lint/UselessAccessModifier: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 4 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 67 + +# Offense count: 4 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +# AllowedMethods: refine +Metrics/BlockLength: + Max: 38 + +# Offense count: 1 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 128 + +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 9 + +# Offense count: 6 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 68 + +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 12 + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: PreferredName. +Naming/RescuedExceptionsVariableName: + Exclude: + - 'Rakefile' + +# Offense count: 3 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Exclude: + - 'spec/**/*' + - 'test/**/*' + - 'Rakefile' + - 'lib/bom_builder.rb' + - 'lib/bom_component.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowedVars. +Style/FetchEnvVar: + Exclude: + - 'lib/bom_helpers.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/FileWrite: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 12 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Exclude: + - '.simplecov' + - 'Gemfile' + - 'Rakefile' + - 'features/fixtures/simple/Gemfile' + - 'features/step_definitions/json_bom_matching.rb' + - 'features/step_definitions/xml_bom_matching.rb' + - 'features/support/env.rb' + - 'features/support/simplecov_support.rb' + - 'lib/bom_component.rb' + - 'spec/bom_component_spec.rb' + - 'spec/bom_helpers_spec.rb' + - 'spec/spec_helper.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowedMethods, AllowedPatterns. +Style/MethodCallWithoutArgsParentheses: + Exclude: + - 'lib/bom_helpers.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: literals, strict +Style/MutableConstant: + Exclude: + - 'lib/bom_builder.rb' + +# Offense count: 2 +Style/OpenStructUse: + Exclude: + - 'lib/bom_builder.rb' + - 'spec/bom_component_spec.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: PreferredDelimiters. +Style/PercentLiteralDelimiters: + Exclude: + - 'Rakefile' + +# Offense count: 19 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: . +# SupportedStyles: same_as_string_literals, single_quotes, double_quotes +Style/QuotedSymbols: + EnforcedStyle: double_quotes + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantBegin: + Exclude: + - 'Rakefile' + +# Offense count: 6 +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantRegexpEscape: + Exclude: + - 'features/step_definitions/json_bom_matching.rb' + - 'features/step_definitions/xml_bom_matching.rb' + +# Offense count: 20 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiterals: + Exclude: + - '.simplecov' + - 'Rakefile' + - 'cyclonedx-ruby.gemspec' + - 'lib/bom_component.rb' + - 'lib/bom_helpers.rb' + - 'spec/bom_component_spec.rb' + - 'spec/bom_helpers_spec.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MinSize. +# SupportedStyles: percent, brackets +Style/SymbolArray: + EnforcedStyle: brackets + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +Style/SymbolLiteral: + Exclude: + - 'lib/bom_component.rb' + +# Offense count: 5 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 237 diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index 23a861c..9d5d0b0 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -32,4 +32,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'cucumber', '~> 8.0' spec.add_development_dependency 'aruba', '~> 2.1' spec.add_development_dependency 'simplecov', '~> 0.22.0' + spec.add_development_dependency 'rubocop', '~> 1.48' end