bundler-sbom 0.1.0
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 +7 -0
- data/README.md +37 -0
- data/lib/bundler/cli/sbom.rb +29 -0
- data/lib/bundler/sbom.rb +126 -0
- data/lib/bundler-sbom.rb +3 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 675a0be818dcf56528e18dcbb7a40bc77a88d31f2f168f5b9c27eb0c21bcdaf6
|
4
|
+
data.tar.gz: c0073141244450742d51354d94ad91359d531ebe66cd7c653c2c5ed47667d5a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d018b46d78d11b87723578ba1a489ad4ff940ef3296bc6f65706b5906269ebb785b64152699b408eb183705625ed7d95d251adfa340cfe82d78727b3f0ad106
|
7
|
+
data.tar.gz: 6a51a7389dd1d22607a6175c8046a3a375a1f7d12f484312f1ce807f63daa497173b897a4bbcf5fd4eb01aa7031798feddc83e9beeb49436dc090b6d9625870d
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Bundler SBOM Plugin
|
2
|
+
|
3
|
+
Generate and analyze Software Bill of Materials (SBOM) for your Ruby projects using Bundler.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install this plugin by running:
|
8
|
+
|
9
|
+
```
|
10
|
+
$ bundler plugin install bundler-sbom
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Generate SBOM
|
16
|
+
|
17
|
+
To generate an SBOM file in SPDX format from your project's Gemfile.lock:
|
18
|
+
|
19
|
+
```
|
20
|
+
$ bundle sbom dump
|
21
|
+
```
|
22
|
+
|
23
|
+
This will create a `bom.json` file in your project directory.
|
24
|
+
|
25
|
+
### Analyze License Information
|
26
|
+
|
27
|
+
To view a summary of licenses used in your project's dependencies:
|
28
|
+
|
29
|
+
```
|
30
|
+
$ bundle sbom license
|
31
|
+
```
|
32
|
+
|
33
|
+
This command will show:
|
34
|
+
- A count of packages using each license
|
35
|
+
- A detailed list of packages grouped by license
|
36
|
+
|
37
|
+
Note: The `license` command requires that you've already generated the SBOM using `bundle sbom dump`.
|
@@ -0,0 +1,29 @@
|
|
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
|
data/lib/bundler/sbom.rb
ADDED
@@ -0,0 +1,126 @@
|
|
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
|
data/lib/bundler-sbom.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bundler-sbom
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- SHIBATA Hiroshi
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-05 00:00:00.000000000 Z
|
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: :development
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '2.0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
description: Generate SPDX format SBOM from Gemfile.lock and analyze license information
|
41
|
+
email:
|
42
|
+
- hsbt@ruby-lang.org
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- README.md
|
48
|
+
- lib/bundler-sbom.rb
|
49
|
+
- lib/bundler/cli/sbom.rb
|
50
|
+
- lib/bundler/sbom.rb
|
51
|
+
homepage: https://github.com/hsbt/hsbt
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubygems_version: 3.7.0.dev
|
70
|
+
specification_version: 4
|
71
|
+
summary: Bundler plugin to generate and analyze SBOM
|
72
|
+
test_files: []
|