gem_guard 0.1.0 → 0.1.6
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 +4 -4
- data/README.md +27 -4
- data/SECURITY.md +58 -0
- data/gem_guard-0.1.0.gem +0 -0
- data/gem_guard.gemspec +4 -4
- data/lib/gem_guard/cli.rb +36 -0
- data/lib/gem_guard/sbom_generator.rb +152 -0
- data/lib/gem_guard/version.rb +1 -1
- data/lib/gem_guard.rb +2 -1
- metadata +24 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '073099f4fd844fee5ffd2b5466fbee6df36a8c5b9d640039efb0cbdb4db89b97'
|
4
|
+
data.tar.gz: 21ba615adb70721d4f9ede82e3a43361a92e72e683c53530504913250ccd7309
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1bc314331a645c4b2d9791f41d852620fc7a977fc7eaf90ea927743f297057f4af93c40da2788422c8c468b11fbb1ad4d80d59f16cb4a0c9c063f37ebed809c
|
7
|
+
data.tar.gz: 1dc4f927542ae0983fb73a0d285c66f61c93960f1128bde659a313bbda24a7e6625d41acfdc48fcadeb8600f78bdb2f6de2b052e072a553aa78a937ad841b7dc
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# GemGuard
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/gem_guard)
|
4
|
-
[](https://github.com/wilburhimself/gem_guard/actions/workflows/ci.yml)
|
5
|
+
[](https://github.com/wilburhimself/gem_guard/actions/workflows/release.yml)
|
5
6
|
[](https://opensource.org/licenses/MIT)
|
7
|
+
[](SECURITY.md)
|
6
8
|
|
7
9
|
Supply chain security and vulnerability management for Ruby gems. GemGuard provides developers with a comprehensive tool to detect, report, and remediate dependency-related security risks.
|
8
10
|
|
@@ -79,13 +81,34 @@ Details:
|
|
79
81
|
|
80
82
|
## Development
|
81
83
|
|
82
|
-
After checking out the repo, run `
|
84
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bundle exec rake standard` to run the linter.
|
83
85
|
|
84
|
-
|
86
|
+
### Running Tests
|
87
|
+
|
88
|
+
```bash
|
89
|
+
bundle exec rspec # Run all tests
|
90
|
+
bundle exec rake standard # Run linter
|
91
|
+
bundle exec rake # Run both tests and linter
|
92
|
+
```
|
93
|
+
|
94
|
+
### Releasing
|
95
|
+
|
96
|
+
Releases are automated via GitHub Actions. To create a new release:
|
97
|
+
|
98
|
+
1. Update the version number in `lib/gem_guard/version.rb`
|
99
|
+
2. Commit and push to the `main` branch
|
100
|
+
3. GitHub Actions will automatically:
|
101
|
+
- Run tests across multiple Ruby versions
|
102
|
+
- Create a git tag
|
103
|
+
- Generate release notes
|
104
|
+
- Create a GitHub release
|
105
|
+
- Publish to RubyGems.org
|
106
|
+
|
107
|
+
The release workflow is triggered only when `lib/gem_guard/version.rb` changes.
|
85
108
|
|
86
109
|
## Contributing
|
87
110
|
|
88
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
111
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/wilburhimself/gem_guard.
|
89
112
|
|
90
113
|
## License
|
91
114
|
|
data/SECURITY.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Security Policy
|
2
|
+
|
3
|
+
## Supported Versions
|
4
|
+
|
5
|
+
We actively support the following versions of GemGuard:
|
6
|
+
|
7
|
+
| Version | Supported |
|
8
|
+
| ------- | ------------------ |
|
9
|
+
| 0.1.x | :white_check_mark: |
|
10
|
+
|
11
|
+
## Reporting a Vulnerability
|
12
|
+
|
13
|
+
If you discover a security vulnerability within GemGuard, please send an email to **security@wilburhimself.com**. All security vulnerabilities will be promptly addressed.
|
14
|
+
|
15
|
+
**Please do not report security vulnerabilities through public GitHub issues.**
|
16
|
+
|
17
|
+
### What to include in your report
|
18
|
+
|
19
|
+
- A description of the vulnerability
|
20
|
+
- Steps to reproduce the issue
|
21
|
+
- Potential impact of the vulnerability
|
22
|
+
- Any suggested fixes (if you have them)
|
23
|
+
|
24
|
+
### Response Timeline
|
25
|
+
|
26
|
+
- **Initial Response**: Within 48 hours
|
27
|
+
- **Status Update**: Within 7 days
|
28
|
+
- **Resolution**: We aim to resolve critical vulnerabilities within 30 days
|
29
|
+
|
30
|
+
### Disclosure Policy
|
31
|
+
|
32
|
+
- We follow responsible disclosure practices
|
33
|
+
- We will acknowledge your contribution in our security advisories (unless you prefer to remain anonymous)
|
34
|
+
- We may offer recognition in our contributors list for significant security reports
|
35
|
+
|
36
|
+
## Security Features
|
37
|
+
|
38
|
+
GemGuard itself implements several security best practices:
|
39
|
+
|
40
|
+
- **Input Validation**: All user inputs are validated and sanitized
|
41
|
+
- **API Security**: Secure communication with vulnerability databases
|
42
|
+
- **Dependency Management**: Regular updates to dependencies
|
43
|
+
- **Code Quality**: Comprehensive testing and static analysis
|
44
|
+
|
45
|
+
## Security Considerations for Users
|
46
|
+
|
47
|
+
When using GemGuard:
|
48
|
+
|
49
|
+
- Keep GemGuard updated to the latest version
|
50
|
+
- Review vulnerability reports carefully before applying fixes
|
51
|
+
- Use GemGuard in your CI/CD pipeline to catch vulnerabilities early
|
52
|
+
- Consider the source and severity of reported vulnerabilities
|
53
|
+
|
54
|
+
## Contact
|
55
|
+
|
56
|
+
For security-related questions or concerns, contact:
|
57
|
+
- Email: security@wilburhimself.com
|
58
|
+
- GitHub: [@wilburhimself](https://github.com/wilburhimself)
|
data/gem_guard-0.1.0.gem
ADDED
Binary file
|
data/gem_guard.gemspec
CHANGED
@@ -8,13 +8,13 @@ Gem::Specification.new do |spec|
|
|
8
8
|
|
9
9
|
spec.summary = "Supply chain security and vulnerability management for Ruby gems"
|
10
10
|
spec.description = "A comprehensive tool to detect, report, and remediate dependency-related security risks in Ruby projects. Includes CVE scanning, SBOM generation, and CI/CD integration."
|
11
|
-
spec.homepage = "https://github.com/
|
11
|
+
spec.homepage = "https://github.com/wilburhimself/gem_guard"
|
12
12
|
spec.license = "MIT"
|
13
13
|
spec.required_ruby_version = ">= 3.0.0"
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
-
spec.metadata["source_code_uri"] = "https://github.com/
|
17
|
-
spec.metadata["changelog_uri"] = "https://github.com/
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/wilburhimself/gem_guard"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/wilburhimself/gem_guard/blob/main/CHANGELOG.md"
|
18
18
|
|
19
19
|
spec.files = Dir.chdir(__dir__) do
|
20
20
|
`git ls-files -z`.split("\x0").reject do |f|
|
@@ -26,10 +26,10 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
|
-
spec.add_dependency "bundler", ">= 2.0"
|
30
29
|
spec.add_dependency "thor", "~> 1.0"
|
31
30
|
spec.add_dependency "json", "~> 2.0"
|
32
31
|
|
32
|
+
spec.add_development_dependency "bundler", ">= 2.0"
|
33
33
|
spec.add_development_dependency "rspec", "~> 3.0"
|
34
34
|
spec.add_development_dependency "standard", "~> 1.3"
|
35
35
|
end
|
data/lib/gem_guard/cli.rb
CHANGED
@@ -22,6 +22,42 @@ module GemGuard
|
|
22
22
|
exit 1 if analysis.has_vulnerabilities?
|
23
23
|
end
|
24
24
|
|
25
|
+
desc "sbom", "Generate Software Bill of Materials (SBOM)"
|
26
|
+
option :format, type: :string, default: "spdx", desc: "SBOM format (spdx, cyclone-dx)"
|
27
|
+
option :lockfile, type: :string, default: "Gemfile.lock", desc: "Path to Gemfile.lock"
|
28
|
+
option :output, type: :string, desc: "Output file path (default: stdout)"
|
29
|
+
option :project, type: :string, default: "ruby-project", desc: "Project name for SBOM"
|
30
|
+
def sbom
|
31
|
+
lockfile_path = options[:lockfile]
|
32
|
+
|
33
|
+
unless File.exist?(lockfile_path)
|
34
|
+
puts "Error: #{lockfile_path} not found"
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
|
38
|
+
dependencies = Parser.new.parse(lockfile_path)
|
39
|
+
generator = SbomGenerator.new
|
40
|
+
|
41
|
+
sbom_data = case options[:format].downcase
|
42
|
+
when "spdx"
|
43
|
+
generator.generate_spdx(dependencies, options[:project])
|
44
|
+
when "cyclone-dx", "cyclonedx"
|
45
|
+
generator.generate_cyclone_dx(dependencies, options[:project])
|
46
|
+
else
|
47
|
+
puts "Error: Unsupported format '#{options[:format]}'. Use 'spdx' or 'cyclone-dx'"
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
output_json = JSON.pretty_generate(sbom_data)
|
52
|
+
|
53
|
+
if options[:output]
|
54
|
+
File.write(options[:output], output_json)
|
55
|
+
puts "SBOM written to #{options[:output]}"
|
56
|
+
else
|
57
|
+
puts output_json
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
25
61
|
desc "version", "Show gem_guard version"
|
26
62
|
def version
|
27
63
|
puts GemGuard::VERSION
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "json"
|
2
|
+
require "digest"
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
module GemGuard
|
6
|
+
class SbomGenerator
|
7
|
+
SPDX_VERSION = "SPDX-2.3"
|
8
|
+
CYCLONE_DX_VERSION = "1.5"
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@document_id = "SPDXRef-DOCUMENT"
|
12
|
+
@creation_time = Time.now.utc.iso8601
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_spdx(dependencies, project_name = "ruby-project")
|
16
|
+
{
|
17
|
+
"spdxVersion" => SPDX_VERSION,
|
18
|
+
"dataLicense" => "CC0-1.0",
|
19
|
+
"SPDXID" => @document_id,
|
20
|
+
"name" => "#{project_name}-sbom",
|
21
|
+
"documentNamespace" => "https://gem-guard.dev/#{project_name}/#{@creation_time}",
|
22
|
+
"creationInfo" => {
|
23
|
+
"created" => @creation_time,
|
24
|
+
"creators" => ["Tool: gem_guard-#{GemGuard::VERSION}"],
|
25
|
+
"licenseListVersion" => "3.21"
|
26
|
+
},
|
27
|
+
"packages" => build_spdx_packages(dependencies, project_name),
|
28
|
+
"relationships" => build_spdx_relationships(dependencies)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_cyclone_dx(dependencies, project_name = "ruby-project")
|
33
|
+
{
|
34
|
+
"bomFormat" => "CycloneDX",
|
35
|
+
"specVersion" => CYCLONE_DX_VERSION,
|
36
|
+
"serialNumber" => "urn:uuid:#{generate_uuid}",
|
37
|
+
"version" => 1,
|
38
|
+
"metadata" => {
|
39
|
+
"timestamp" => @creation_time,
|
40
|
+
"tools" => [
|
41
|
+
{
|
42
|
+
"vendor" => "GemGuard",
|
43
|
+
"name" => "gem_guard",
|
44
|
+
"version" => GemGuard::VERSION
|
45
|
+
}
|
46
|
+
],
|
47
|
+
"component" => {
|
48
|
+
"type" => "application",
|
49
|
+
"name" => project_name,
|
50
|
+
"version" => "1.0.0"
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"components" => build_cyclone_dx_components(dependencies)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def build_spdx_packages(dependencies, project_name)
|
60
|
+
packages = []
|
61
|
+
|
62
|
+
# Add root package
|
63
|
+
packages << {
|
64
|
+
"SPDXID" => "SPDXRef-Package-#{sanitize_name(project_name)}",
|
65
|
+
"name" => project_name,
|
66
|
+
"downloadLocation" => "NOASSERTION",
|
67
|
+
"filesAnalyzed" => false,
|
68
|
+
"copyrightText" => "NOASSERTION"
|
69
|
+
}
|
70
|
+
|
71
|
+
# Add dependency packages
|
72
|
+
dependencies.each_with_index do |dep, index|
|
73
|
+
packages << {
|
74
|
+
"SPDXID" => "SPDXRef-Package-#{sanitize_name(dep.name)}",
|
75
|
+
"name" => dep.name,
|
76
|
+
"versionInfo" => dep.version,
|
77
|
+
"downloadLocation" => gem_download_url(dep.name, dep.version),
|
78
|
+
"filesAnalyzed" => false,
|
79
|
+
"homepage" => gem_homepage_url(dep.name),
|
80
|
+
"copyrightText" => "NOASSERTION",
|
81
|
+
"externalRefs" => [
|
82
|
+
{
|
83
|
+
"referenceCategory" => "PACKAGE-MANAGER",
|
84
|
+
"referenceType" => "purl",
|
85
|
+
"referenceLocator" => "pkg:gem/#{dep.name}@#{dep.version}"
|
86
|
+
}
|
87
|
+
]
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
packages
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_spdx_relationships(dependencies)
|
95
|
+
relationships = []
|
96
|
+
|
97
|
+
dependencies.each do |dep|
|
98
|
+
relationships << {
|
99
|
+
"spdxElementId" => @document_id,
|
100
|
+
"relationshipType" => "DESCRIBES",
|
101
|
+
"relatedSpdxElement" => "SPDXRef-Package-#{sanitize_name(dep.name)}"
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
relationships
|
106
|
+
end
|
107
|
+
|
108
|
+
def build_cyclone_dx_components(dependencies)
|
109
|
+
dependencies.map do |dep|
|
110
|
+
{
|
111
|
+
"type" => "library",
|
112
|
+
"bom-ref" => "pkg:gem/#{dep.name}@#{dep.version}",
|
113
|
+
"name" => dep.name,
|
114
|
+
"version" => dep.version,
|
115
|
+
"purl" => "pkg:gem/#{dep.name}@#{dep.version}",
|
116
|
+
"externalReferences" => [
|
117
|
+
{
|
118
|
+
"type" => "distribution",
|
119
|
+
"url" => gem_download_url(dep.name, dep.version)
|
120
|
+
},
|
121
|
+
{
|
122
|
+
"type" => "website",
|
123
|
+
"url" => gem_homepage_url(dep.name)
|
124
|
+
}
|
125
|
+
]
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def sanitize_name(name)
|
131
|
+
name.gsub(/[^a-zA-Z0-9\-_]/, "-")
|
132
|
+
end
|
133
|
+
|
134
|
+
def gem_download_url(name, version)
|
135
|
+
"https://rubygems.org/downloads/#{name}-#{version}.gem"
|
136
|
+
end
|
137
|
+
|
138
|
+
def gem_homepage_url(name)
|
139
|
+
"https://rubygems.org/gems/#{name}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def generate_uuid
|
143
|
+
# Simple UUID v4 generation
|
144
|
+
bytes = Array.new(16) { rand(256) }
|
145
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40 # Version 4
|
146
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80 # Variant bits
|
147
|
+
|
148
|
+
format = "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
149
|
+
format % bytes
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/gem_guard/version.rb
CHANGED
data/lib/gem_guard.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require_relative "gem_guard/version"
|
2
|
-
require_relative "gem_guard/cli"
|
3
2
|
require_relative "gem_guard/parser"
|
4
3
|
require_relative "gem_guard/vulnerability_fetcher"
|
5
4
|
require_relative "gem_guard/analyzer"
|
6
5
|
require_relative "gem_guard/reporter"
|
6
|
+
require_relative "gem_guard/sbom_generator"
|
7
|
+
require_relative "gem_guard/cli"
|
7
8
|
|
8
9
|
module GemGuard
|
9
10
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,54 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gem_guard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wilbur Suero
|
8
|
+
autorequire:
|
8
9
|
bindir: exe
|
9
10
|
cert_chain: []
|
10
11
|
date: 2025-08-09 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
|
-
name:
|
14
|
+
name: thor
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- - "
|
17
|
+
- - "~>"
|
17
18
|
- !ruby/object:Gem::Version
|
18
|
-
version: '
|
19
|
+
version: '1.0'
|
19
20
|
type: :runtime
|
20
21
|
prerelease: false
|
21
22
|
version_requirements: !ruby/object:Gem::Requirement
|
22
23
|
requirements:
|
23
|
-
- - "
|
24
|
+
- - "~>"
|
24
25
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
26
|
+
version: '1.0'
|
26
27
|
- !ruby/object:Gem::Dependency
|
27
|
-
name:
|
28
|
+
name: json
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
31
|
- - "~>"
|
31
32
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
+
version: '2.0'
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
36
|
version_requirements: !ruby/object:Gem::Requirement
|
36
37
|
requirements:
|
37
38
|
- - "~>"
|
38
39
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
40
|
+
version: '2.0'
|
40
41
|
- !ruby/object:Gem::Dependency
|
41
|
-
name:
|
42
|
+
name: bundler
|
42
43
|
requirement: !ruby/object:Gem::Requirement
|
43
44
|
requirements:
|
44
|
-
- - "
|
45
|
+
- - ">="
|
45
46
|
- !ruby/object:Gem::Version
|
46
47
|
version: '2.0'
|
47
|
-
type: :
|
48
|
+
type: :development
|
48
49
|
prerelease: false
|
49
50
|
version_requirements: !ruby/object:Gem::Requirement
|
50
51
|
requirements:
|
51
|
-
- - "
|
52
|
+
- - ">="
|
52
53
|
- !ruby/object:Gem::Version
|
53
54
|
version: '2.0'
|
54
55
|
- !ruby/object:Gem::Dependency
|
@@ -93,23 +94,27 @@ files:
|
|
93
94
|
- LICENSE.txt
|
94
95
|
- README.md
|
95
96
|
- Rakefile
|
97
|
+
- SECURITY.md
|
96
98
|
- exe/gem_guard
|
99
|
+
- gem_guard-0.1.0.gem
|
97
100
|
- gem_guard.gemspec
|
98
101
|
- lib/gem_guard.rb
|
99
102
|
- lib/gem_guard/analyzer.rb
|
100
103
|
- lib/gem_guard/cli.rb
|
101
104
|
- lib/gem_guard/parser.rb
|
102
105
|
- lib/gem_guard/reporter.rb
|
106
|
+
- lib/gem_guard/sbom_generator.rb
|
103
107
|
- lib/gem_guard/version.rb
|
104
108
|
- lib/gem_guard/vulnerability_fetcher.rb
|
105
109
|
- plan.md
|
106
|
-
homepage: https://github.com/
|
110
|
+
homepage: https://github.com/wilburhimself/gem_guard
|
107
111
|
licenses:
|
108
112
|
- MIT
|
109
113
|
metadata:
|
110
|
-
homepage_uri: https://github.com/
|
111
|
-
source_code_uri: https://github.com/
|
112
|
-
changelog_uri: https://github.com/
|
114
|
+
homepage_uri: https://github.com/wilburhimself/gem_guard
|
115
|
+
source_code_uri: https://github.com/wilburhimself/gem_guard
|
116
|
+
changelog_uri: https://github.com/wilburhimself/gem_guard/blob/main/CHANGELOG.md
|
117
|
+
post_install_message:
|
113
118
|
rdoc_options: []
|
114
119
|
require_paths:
|
115
120
|
- lib
|
@@ -124,7 +129,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
129
|
- !ruby/object:Gem::Version
|
125
130
|
version: '0'
|
126
131
|
requirements: []
|
127
|
-
rubygems_version: 3.
|
132
|
+
rubygems_version: 3.5.22
|
133
|
+
signing_key:
|
128
134
|
specification_version: 4
|
129
135
|
summary: Supply chain security and vulnerability management for Ruby gems
|
130
136
|
test_files: []
|