bundler-sbom 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11988f0f90e45b23bb081c4c27781e5242f387d39e658dbde782497aa5699d4b
4
- data.tar.gz: f588574646c487ff5099d155f2184ebad49f05a4821706d233f33b0c7a0ff0e6
3
+ metadata.gz: bb32eb6e21ec3b09fe1d3d199b978c44313f119ee57bb9d3899b20ae443020c0
4
+ data.tar.gz: 36b4b1b637fbafa93ac463418e5e26330146cff96b7c2e76733bc7c5b4a2cfc9
5
5
  SHA512:
6
- metadata.gz: 68ea6d07b959c6f441329583ddb62953cc348dacb17bf3f9da85414f69aa53fcc7cc4f2f736bc149cd7da434790baa722d19058f3f822b920370107128ea9fa4
7
- data.tar.gz: e92b354809e79a8d3e91b6fe170b2ceaa9caa2d7393a70c7b537c951f983d6ac5f91d5fcc5f56ede207884559616d1e42451cb3dc2d5b9f99fc829bc769dbedf
6
+ metadata.gz: 39825222126b541eaf3df0b04c5b9784ce7cdc68d6fd837f642cad6e6ce5e6196a709a31154565f97efaea0ab8f1f483417daada360e331990a675880f3f75e6
7
+ data.tar.gz: f95ddbec1b92a9eeffd0732f31d30005e3fb36d85f3c381454977a7130e24630e32fe4d6fbfbf005f3cefaaa35d5bc264c92aa29403d64aff33050797727505b
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "rake"
7
+ gem "rspec"
8
+ gem "simplecov", require: false
9
+ gem "rspec-its"
10
+ gem "rspec-mocks"
11
+ end
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,31 @@
1
+ require "json"
2
+ require "bundler/sbom/generator"
3
+
4
+ module Bundler
5
+ module Sbom
6
+ class CLI < Thor
7
+ desc "dump", "Generate SBOM and save to bom.json"
8
+ def dump
9
+ sbom = Bundler::Sbom::Generator.generate_sbom
10
+ File.write("bom.json", JSON.pretty_generate(sbom))
11
+ Bundler.ui.info("Generated SBOM at bom.json")
12
+ end
13
+
14
+ desc "license", "Display license report from existing bom.json"
15
+ def license
16
+ unless File.exist?("bom.json")
17
+ Bundler.ui.error("Error: bom.json not found. Run 'bundle sbom dump' first.")
18
+ exit 1
19
+ end
20
+
21
+ begin
22
+ sbom = JSON.parse(File.read("bom.json"))
23
+ Bundler::Sbom::Generator.display_license_report(sbom)
24
+ rescue JSON::ParserError
25
+ Bundler.ui.error("Error: bom.json is not a valid JSON file")
26
+ exit 1
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,118 @@
1
+ require "bundler"
2
+ require "securerandom"
3
+
4
+ module Bundler
5
+ module Sbom
6
+ class Generator
7
+ def self.generate_sbom
8
+ lockfile_path = Bundler.default_lockfile
9
+ unless lockfile_path.exist?
10
+ abort "No Gemfile.lock found. Run `bundle install` first."
11
+ end
12
+
13
+ lockfile = Bundler::LockfileParser.new(lockfile_path.read)
14
+ document_name = File.basename(Dir.pwd)
15
+ spdx_id = SecureRandom.uuid
16
+
17
+ sbom = {
18
+ "SPDXID" => "SPDXRef-DOCUMENT",
19
+ "spdxVersion" => "SPDX-2.2",
20
+ "creationInfo" => {
21
+ "created" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
22
+ "creators" => ["Tool: bundle-sbom"],
23
+ "licenseListVersion" => "3.17"
24
+ },
25
+ "name" => document_name,
26
+ "dataLicense" => "CC0-1.0",
27
+ "documentNamespace" => "https://spdx.org/spdxdocs/#{document_name}-#{spdx_id}",
28
+ "packages" => []
29
+ }
30
+
31
+ lockfile.specs.each do |spec|
32
+ begin
33
+ gemspec = Gem::Specification.find_by_name(spec.name, spec.version)
34
+ licenses = []
35
+ if gemspec
36
+ if gemspec.license && !gemspec.license.empty?
37
+ licenses << gemspec.license
38
+ end
39
+
40
+ if gemspec.licenses && !gemspec.licenses.empty?
41
+ licenses.concat(gemspec.licenses)
42
+ end
43
+
44
+ licenses.uniq!
45
+ end
46
+
47
+ license_string = licenses.empty? ? "NOASSERTION" : licenses.join(", ")
48
+ rescue Gem::LoadError
49
+ license_string = "NOASSERTION"
50
+ end
51
+
52
+ package = {
53
+ "SPDXID" => "SPDXRef-Package-#{spec.name}",
54
+ "name" => spec.name,
55
+ "versionInfo" => spec.version.to_s,
56
+ "downloadLocation" => "NOASSERTION",
57
+ "filesAnalyzed" => false,
58
+ "licenseConcluded" => license_string,
59
+ "licenseDeclared" => license_string,
60
+ "supplier" => "NOASSERTION",
61
+ "externalRefs" => [
62
+ {
63
+ "referenceCategory" => "PACKAGE_MANAGER",
64
+ "referenceType" => "purl",
65
+ "referenceLocator" => "pkg:gem/#{spec.name}@#{spec.version}"
66
+ }
67
+ ]
68
+ }
69
+ sbom["packages"] << package
70
+ end
71
+
72
+ sbom
73
+ end
74
+
75
+ def self.display_license_report(sbom)
76
+ license_count = analyze_licenses(sbom)
77
+ sorted_licenses = license_count.sort_by { |_, count| -count }
78
+
79
+ puts "=== License Usage in SBOM ==="
80
+ puts "Total packages: #{sbom["packages"].size}"
81
+ puts
82
+
83
+ sorted_licenses.each do |license, count|
84
+ puts "#{license}: #{count} package(s)"
85
+ end
86
+
87
+ puts "\n=== Packages by License ==="
88
+ sorted_licenses.each do |license, _|
89
+ packages = sbom["packages"].select do |package|
90
+ if package["licenseDeclared"].include?(",")
91
+ package["licenseDeclared"].split(",").map(&:strip).include?(license)
92
+ else
93
+ package["licenseDeclared"] == license
94
+ end
95
+ end
96
+
97
+ puts "\n#{license} (#{packages.size} package(s)):"
98
+ packages.each do |package|
99
+ puts " - #{package["name"]} (#{package["versionInfo"]})"
100
+ end
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def self.analyze_licenses(sbom)
107
+ license_count = Hash.new(0)
108
+ sbom["packages"].each do |package|
109
+ licenses = package["licenseDeclared"].split(",").map(&:strip)
110
+ licenses.each do |license|
111
+ license_count[license] += 1
112
+ end
113
+ end
114
+ license_count
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,5 @@
1
+ module Bundler
2
+ module Sbom
3
+ VERSION = "0.1.5"
4
+ end
5
+ end
data/lib/bundler/sbom.rb CHANGED
@@ -1,126 +1,3 @@
1
- require "bundler"
2
- require "json"
3
- require "securerandom"
4
- require "rubygems"
5
-
6
- module Bundler
7
- module Sbom
8
- class Generator
9
- def self.generate_sbom
10
- lockfile_path = Bundler.default_lockfile
11
- unless lockfile_path.exist?
12
- abort "No Gemfile.lock found. Run `bundle install` first."
13
- end
14
-
15
- lockfile = Bundler::LockfileParser.new(lockfile_path.read)
16
- document_name = File.basename(Dir.pwd)
17
- spdx_id = SecureRandom.uuid
18
-
19
- sbom = {
20
- "SPDXID" => "SPDXRef-DOCUMENT",
21
- "spdxVersion" => "SPDX-2.2",
22
- "creationInfo" => {
23
- "created" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
24
- "creators" => ["Tool: bundle-sbom"],
25
- "licenseListVersion" => "3.17"
26
- },
27
- "name" => document_name,
28
- "dataLicense" => "CC0-1.0",
29
- "documentNamespace" => "https://spdx.org/spdxdocs/#{document_name}-#{spdx_id}",
30
- "packages" => []
31
- }
32
-
33
- lockfile.specs.each do |spec|
34
- begin
35
- gemspec = Gem::Specification.find_by_name(spec.name, spec.version)
36
- licenses = []
37
- if gemspec
38
- if gemspec.license && !gemspec.license.empty?
39
- licenses << gemspec.license
40
- end
41
-
42
- if gemspec.licenses && !gemspec.licenses.empty?
43
- licenses.concat(gemspec.licenses)
44
- end
45
-
46
- licenses.uniq!
47
- end
48
-
49
- license_string = licenses.empty? ? "NOASSERTION" : licenses.join(", ")
50
- rescue Gem::LoadError
51
- license_string = "NOASSERTION"
52
- end
53
-
54
- package = {
55
- "SPDXID" => "SPDXRef-Package-#{spec.name}",
56
- "name" => spec.name,
57
- "versionInfo" => spec.version.to_s,
58
- "downloadLocation" => "NOASSERTION",
59
- "filesAnalyzed" => false,
60
- "licenseConcluded" => license_string,
61
- "licenseDeclared" => license_string,
62
- "supplier" => "NOASSERTION",
63
- "externalRefs" => [
64
- {
65
- "referenceCategory" => "PACKAGE_MANAGER",
66
- "referenceType" => "purl",
67
- "referenceLocator" => "pkg:gem/#{spec.name}@#{spec.version}"
68
- }
69
- ]
70
- }
71
- sbom["packages"] << package
72
- end
73
-
74
- sbom
75
- end
76
-
77
- def self.analyze_licenses(sbom)
78
- license_count = Hash.new(0)
79
-
80
- sbom["packages"].each do |package|
81
- license = package["licenseDeclared"]
82
-
83
- if license.include?(",")
84
- licenses = license.split(",").map(&:strip)
85
- licenses.each do |lic|
86
- license_count[lic] += 1
87
- end
88
- else
89
- license_count[license] += 1
90
- end
91
- end
92
-
93
- license_count
94
- end
95
-
96
- def self.display_license_report(sbom)
97
- license_count = analyze_licenses(sbom)
98
- sorted_licenses = license_count.sort_by { |_, count| -count }
99
-
100
- puts "=== License Usage in SBOM ==="
101
- puts "Total packages: #{sbom["packages"].size}"
102
- puts
103
-
104
- sorted_licenses.each do |license, count|
105
- puts "#{license}: #{count} package(s)"
106
- end
107
-
108
- puts "\n=== Packages by License ==="
109
- sorted_licenses.each do |license, _|
110
- packages = sbom["packages"].select do |package|
111
- if package["licenseDeclared"].include?(",")
112
- package["licenseDeclared"].split(",").map(&:strip).include?(license)
113
- else
114
- package["licenseDeclared"] == license
115
- end
116
- end
117
-
118
- puts "\n#{license} (#{packages.size} package(s)):"
119
- packages.each do |package|
120
- puts " - #{package["name"]} (#{package["versionInfo"]})"
121
- end
122
- end
123
- end
124
- end
125
- end
126
- end
1
+ require "bundler/sbom/version"
2
+ require "bundler/sbom/generator"
3
+ require "bundler/sbom/cli"
data/plugins.rb CHANGED
@@ -1,11 +1,14 @@
1
- require "bundler/cli/sbom"
1
+ require "bundler"
2
+ require "bundler/sbom"
2
3
 
3
- Bundler::Plugin::API.command "sbom" do |command|
4
- command.command "dump" do
5
- Bundler::CLI::Sbom.new.dump
6
- end
4
+ module Bundler
5
+ module Sbom
6
+ class Plugin < ::Bundler::Plugin::API
7
+ command "sbom"
7
8
 
8
- command.command "license" do
9
- Bundler::CLI::Sbom.new.license
9
+ def exec(command_name, args)
10
+ ::Bundler::Sbom::CLI.start(args)
11
+ end
12
+ end
10
13
  end
11
- end
14
+ end
metadata CHANGED
@@ -1,28 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-sbom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - SHIBATA Hiroshi
8
8
  bindir: exe
9
9
  cert_chain: []
10
10
  date: 2025-03-05 00:00:00.000000000 Z
11
- dependencies: []
12
- description: Generate SPDX format SBOM from Gemfile.lock and analyze license information
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bundler
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ description: Generate CycloneDX SBOM(Software Bill of Materials) files with Bundler
13
27
  email:
14
28
  - hsbt@ruby-lang.org
15
29
  executables: []
16
30
  extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
33
+ - Gemfile
19
34
  - README.md
20
- - lib/bundler/cli/sbom.rb
35
+ - Rakefile
21
36
  - lib/bundler/sbom.rb
37
+ - lib/bundler/sbom/cli.rb
38
+ - lib/bundler/sbom/generator.rb
39
+ - lib/bundler/sbom/version.rb
22
40
  - plugins.rb
23
41
  homepage: https://github.com/hsbt/bundler-sbom
24
- licenses:
25
- - MIT
42
+ licenses: []
26
43
  metadata:
27
44
  homepage_uri: https://github.com/hsbt/bundler-sbom
28
45
  source_code_uri: https://github.com/hsbt/bundler-sbom
@@ -35,7 +52,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
52
  requirements:
36
53
  - - ">="
37
54
  - !ruby/object:Gem::Version
38
- version: '0'
55
+ version: 2.6.0
39
56
  required_rubygems_version: !ruby/object:Gem::Requirement
40
57
  requirements:
41
58
  - - ">="
@@ -44,5 +61,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
61
  requirements: []
45
62
  rubygems_version: 3.6.2
46
63
  specification_version: 4
47
- summary: Bundler plugin to generate and analyze SBOM
64
+ summary: Generate CycloneDX SBOM(Software Bill of Materials) files with Bundler
48
65
  test_files: []
@@ -1,29 +0,0 @@
1
- require "bundler/cli"
2
- require "bundler/sbom"
3
-
4
- module Bundler
5
- class CLI::Sbom
6
- def initialize(options = {})
7
- @options = options
8
- end
9
-
10
- def dump
11
- sbom = Bundler::Sbom::Generator.generate_sbom
12
- File.write("bom.json", JSON.pretty_generate(sbom))
13
- Bundler.ui.info "Generated SBOM at bom.json"
14
- end
15
-
16
- def license
17
- begin
18
- sbom = JSON.parse(File.read("bom.json"))
19
- Bundler::Sbom::Generator.display_license_report(sbom)
20
- rescue Errno::ENOENT
21
- Bundler.ui.error "Error: bom.json not found. Run 'bundle sbom dump' first."
22
- exit 1
23
- rescue JSON::ParserError
24
- Bundler.ui.error "Error: bom.json is not a valid JSON file"
25
- exit 1
26
- end
27
- end
28
- end
29
- end