✨ --spec-version, --include-metadata, --enrich-components, --gem-server#50
✨ --spec-version, --include-metadata, --enrich-components, --gem-server#50pboling wants to merge 14 commits into
Conversation
- make setup, specs_list private methods Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
- When provided, metadata.tools identifies this producer: - vendor: CycloneDX - name: cyclonedx-ruby - version: the gem’s version - Emitted for both JSON and XML, and only when the selected spec supports metadata (>= 1.2). - Help and README updated. - features/metadata_tools.feature (integration) - spec/cyclonedx/metadata_tools_spec.rb (unit, offline-safe) Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
- Updated Cyclonedx::BomBuilder to add:
- CLI: --enrich-components to opt-in enrichment.
- Pass include_enrichment to build_bom(...).
- Note: This does not alter default outputs; enrichment only applies with the flag.
- Updated Cyclonedx::BomHelpers:
- build_bom supports include_enrichment and passes it to both JSON and XML builders.
- build_json_bom adds bom-ref and publisher via BomComponent when include_enrichment: true.
- build_bom_xml adds:
- bom-ref attribute on <component> using purl.
- <publisher>first_author</publisher> if authors are present (first item split on commas/ampersands).
- Added a small _get helper to read properties from either Hash or OpenStruct-like objects.
- Updated Cyclonedx::BomComponent:
- Added optional keyword parameter include_enrichment: false to hash_val.
- When true, include:
- "bom-ref": purl (if present)
- "publisher": first author (if present)
- Made property access robust across Hash/OpenStruct.
- Ensured hashes is an array with an object { alg, content } as expected by existing specs.
- Added spec/cyclonedx/component_enrichment_spec.rb:
- Verifies JSON has bom-ref and publisher when include_enrichment: true and omits them otherwise.
- Verifies XML has bom-ref attribute and <publisher> when include_enrichment: true and omits otherwise.
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
- Fix link to renamed LICENSE => LICENSE.txt Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Added --gem-server flag to allow users to specify a custom gem server for fetching gem metadata instead of using the hardcoded default. - Added --gem-server URL option in Cyclonedx::BomBuilder command-line parser - Stores custom server URL in @options[:gem_server] for use during BOM generation - When specified, passes the custom gem_server to get_gem() calls - Defaults to gem.coop when not specified, maintaining backward compatibility - Modified Cyclonedx::BomHelpers.get_gem to accept optional gem_server parameter - Defaults to 'https://gem.coop' when nil - Strips trailing slashes from gem_server URLs for consistency - Constructs gem metadata API URL using provided server - Updated get_gem call in bom_builder.rb (line 222) to pass @options[:gem_server] Unit tests (spec/cyclonedx/bom_helpers_spec.rb): - Validates default behavior uses gem.coop when gem_server is not provided or nil - Verifies custom gem server URLs are used correctly - Tests trailing slash removal from custom server URLs - Confirms rubygems.org works as a custom server - Maintains existing error handling tests Cucumber tests (features/gem_server.feature): - Validates default gem.coop behavior when --gem-server not specified - Tests custom gem server with https://rubygems.org - Tests custom gem server with trailing slash normalization - Verifies help text displays the --gem-server option Users can now: - Use private gem servers: --gem-server https://internal.company.com - Use rubygems.org directly: --gem-server https://rubygems.org - Use alternate public mirrors - Default to gem.coop without any configuration change Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR adds support for CycloneDX spec version selection via the --spec-version flag and introduces several new CLI options to enhance BOM generation capabilities. The changes include optional metadata embedding, component enrichment features, and configurable gem server selection.
Key Changes
- Added three new CLI flags:
--include-metadata(embeds tool identity in BOMs),--enrich-components(adds bom-ref and publisher fields), and--gem-server(allows custom gem repository configuration) - Changed default gem server from rubygems.org to gem.coop across the codebase
- Refactored gem object field access to support both Hash and OpenStruct-like objects
Reviewed changes
Copilot reviewed 15 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/cyclonedx/bom_builder.rb | Added CLI option parsing for new flags and spec version validation logic |
| lib/cyclonedx/bom_helpers.rb | Implemented metadata.tools support, component enrichment, custom gem server configuration, and helper methods for object field access |
| lib/cyclonedx/bom_component.rb | Refactored to use a fetch method for accessing gem object fields and added enrichment support |
| lib/cyclonedx/ruby.rb | Reordered requires to resolve dependency issues |
| spec/cyclonedx/metadata_tools_spec.rb | Added unit tests for metadata.tools emission in JSON and XML formats |
| spec/cyclonedx/component_enrichment_spec.rb | Added unit tests for component enrichment features (bom-ref and publisher) |
| spec/cyclonedx/bom_helpers_spec.rb | Added tests for gem server configuration including default, custom, and error handling scenarios |
| features/metadata_tools.feature | Added Cucumber scenarios testing metadata inclusion in both JSON and XML BOMs |
| features/gem_server.feature | Added Cucumber scenarios for custom gem server functionality |
| features/help.feature | Updated help text to reflect new CLI options |
| README.md | Updated documentation with new CLI flags and changed gem badge link |
| Gemfile, Gemfile.lock, features/fixtures/simple/Gemfile | Changed gem source from rubygems.org to gem.coop |
| CODE_OF_CONDUCT.md | Added Contributor Covenant Code of Conduct |
| .rubocop_todo.yml | Updated RuboCop configuration to reflect new code metrics |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
It isn't clear to me why this gem depends on activesupport. It seems to be something related to the Hash core extensions. I am going to try to narrow it down and remove the dependency in a new PR. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: |7eter l-|. l3oling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
Signed-off-by: Peter H. Boling <peter.boling@gmail.com>
1158d73 to
f477f8d
Compare
|
@jkowalleck @andrew Done, specs fixed, script fixed, everything fixed. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 19 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def _get(obj, key) | ||
| if obj.respond_to?(:[]) && obj[key] | ||
| obj[key] | ||
| elsif obj.respond_to?(key) | ||
| obj.public_send(key) | ||
| end |
There was a problem hiding this comment.
The logic in the _get method has a bug. The condition obj.respond_to?(:[]) && obj[key] will return nil if the key exists but has a falsy value (nil, false, 0, empty string). The method should check for key existence rather than truthiness of the value. Consider using obj.respond_to?(:key?) && obj.key?(key) for Hash-like objects, or check the presence separately from retrieving the value.
| if @project_path | ||
| begin | ||
| @logger.info("Changing directory to Ruby project directory located at #{@provided_path}") | ||
| Dir.chdir @project_path | ||
| rescue StandardError => e | ||
| @logger.error("Unable to change directory to Ruby project directory located at #{@provided_path}. #{e.message}: #{Array(e.backtrace).join("\n")}") | ||
| abort | ||
| end | ||
| else | ||
| @logger.error("project_path could not be determined. path provided was: #{@options[:path]}") |
There was a problem hiding this comment.
The condition if @project_path on line 117 is redundant. At line 114, @project_path is assigned File.expand_path(@options[:path]), and since we've already validated that @options[:path] exists (line 103) and is a directory (line 108), File.expand_path will never return nil. The else branch on lines 125-128 is unreachable code.
| if @project_path | |
| begin | |
| @logger.info("Changing directory to Ruby project directory located at #{@provided_path}") | |
| Dir.chdir @project_path | |
| rescue StandardError => e | |
| @logger.error("Unable to change directory to Ruby project directory located at #{@provided_path}. #{e.message}: #{Array(e.backtrace).join("\n")}") | |
| abort | |
| end | |
| else | |
| @logger.error("project_path could not be determined. path provided was: #{@options[:path]}") | |
| begin | |
| @logger.info("Changing directory to Ruby project directory located at #{@provided_path}") | |
| Dir.chdir @project_path | |
| rescue StandardError => e | |
| @logger.error("Unable to change directory to Ruby project directory located at #{@provided_path}. #{e.message}: #{Array(e.backtrace).join("\n")}") |
jkowalleck
left a comment
There was a problem hiding this comment.
hm, i find the review hard. it is a mix of multiple scopes, goals, and therefore, i'd decline the review.
please divide this PR into multiple PRs - each with its own scope.
Think like this: if I wanted a change (feature/fix/etc), then I would write one ticket/request per change, and therefore each change will have its own discussion of expected outcome/cases/non-cases/etc, its own pull request, its own domain experts, its own review - and therefore its own pace.
Mixing multiple things in one PR makes review cumbersome and slow. - which blocks rapid evolution.
There was a problem hiding this comment.
thats a copy of https://github.com/CycloneDX/.github/blob/master/CODE_OF_CONDUCT.md ?
Anyway, it is not needed, as the original one appliesalready - see https://github.com/CycloneDX/cyclonedx-ruby-gem?tab=coc-ov-file#readme
so, could this file be removed, then?
| # frozen_string_literal: true | ||
|
|
||
| source 'https://rubygems.org' | ||
| source 'https://gem.coop/' |
There was a problem hiding this comment.
yep,
moving away from the money-driven ting to an alternative, free, community-driven one - 👍
| # CycloneDX Ruby Gem | ||
|
|
||
| [](https://rubygems.org/gems/cyclonedx-ruby) | ||
| [](https://bestgems.org/gems/cyclonedx-ruby) |
There was a problem hiding this comment.
why this change?
the button linking to the primary download source is very common,
why link to some download stats page instead?
There was a problem hiding this comment.
Just a preference to not link to RG.O. If you prefer the old way I'll leave it alone! I like the additional information on bestgems, which is also a community resource, but I'm not strongly inclined either way.
There was a problem hiding this comment.
no preferences, just asking.
please split such changes to dedicated individual pull requests which may move on their own pace.
There was a problem hiding this comment.
Yes! I plan to do that soon!
| `-o, --output bom_file_path` Path to output the bom file | ||
| `-f, --format bom_output_format` Output format for bom. Supported: xml (default), json | ||
| `-s, --spec-version version` CycloneDX spec version to target (default: 1.7). Supported: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 | ||
| `--include-metadata` Include metadata.tools identifying cyclonedx-ruby as the producer |
There was a problem hiding this comment.
i dont see a reason to hide this feature behind a feature switch.
it should be always the case: add the tool itself to metadata - whatsoever.
There was a problem hiding this comment.
Agree, will make it built-in default for spec versions that support it.
| # JSON at CycloneDX 1.2 to a custom path | ||
| cyclonedx-ruby -p /path/to/ruby/project -f json -s 1.2 -o bom/out.json | ||
|
|
||
| # Include producer metadata and validate |
There was a problem hiding this comment.
[...] and validate
where comes the validate from?
There was a problem hiding this comment.
That's vestigial, it was a really big rebase getting it off of the validation feature. I'll pull this apart into separate PRs, and make metadata inclusion a built-in default for spec versions that support it (v1.2+).
|
|
||
| $stdout.sync = true | ||
|
|
||
| require "rubygems" |
There was a problem hiding this comment.
You are right to question that. It should not be needed. It wasn't working without it on my machine, but I think it may just be an edge case of attempting to run it from the source checkout versus a real installed gem that has the benefit of the bin script wrapper (which already does require "rubygems") and the installed gems lookup being ahead of other scripts. Since I don't have the gem installed locally, and am just working on the source I needed it to get it to run, until I built and installed the gem from the source. For normal usage it is not needed at all, and I forgot I had added it for testing.
Will remove.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: |7eter l-|. l3oling <peter.boling@gmail.com>
✨ --include-metadata (metadata.tools) & --enrich-components
CLI and wiring
--include-metadata- vendor: CycloneDX
- name: cyclonedx-ruby
- version: the gem’s version
--enrich-componentsJSON and XML emission
Component shape
Tests
✨ --gem-server: Configurable Gem Server URL
Added --gem-server flag to allow users to specify a custom gem server
for fetching gem metadata instead of using the hardcoded default.
CLI changes
Core implementation
Tests
Unit tests (spec/cyclonedx/bom_helpers_spec.rb):
Cucumber tests (features/gem_server.feature):
Use cases
Users can now:
Signed-off-by: Peter H. Boling peter.boling@gmail.com