bundler-trivy 0.1.4 → 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 +4 -4
- data/README.md +1 -1
- data/lib/bundler/trivy/config.rb +12 -9
- data/lib/bundler/trivy/plugin.rb +7 -3
- data/lib/bundler/trivy/reporter.rb +9 -5
- data/lib/bundler/trivy/scanner.rb +1 -1
- data/lib/bundler/trivy/version.rb +1 -1
- data/lib/bundler/trivy/vulnerability.rb +13 -17
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a7b59afe9e3d14eaedb5644c7c421ac940519940001ac27fc7bdbcba8c9e9f78
|
|
4
|
+
data.tar.gz: 95b5980cdd1bd8f25e166444e29d0907d05dff6d9dfaf37ac3a4969f6dd5ecd3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 036bf8d9aedd742df8adec69f21f4c27412d7b705ff056c783248a90aae823827216efebafc854eea4bac01cb3ee80e6e2d577686c5f74da80aacb6b2c75b875
|
|
7
|
+
data.tar.gz: 35c039953350c276732df80b6934f0d079dd33543b067832c8ebe4e16fd4f63fddf7100a715e56243f7a63f5a97badfd9f56c3f0befb3cf4692fa1b27bfbcfd9
|
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ A Bundler plugin that automatically integrates [Trivy](https://trivy.dev/) secur
|
|
|
12
12
|
- **CVE Ignore List**: Temporary ignore vulnerabilities with expiration dates
|
|
13
13
|
- **Multiple Output Formats**: Terminal (default), JSON, and compact modes
|
|
14
14
|
- **Detailed Reporting**: Clear vulnerability summaries with fix recommendations
|
|
15
|
-
- **Zero Dependencies**: Lightweight plugin with minimal runtime dependencies
|
|
15
|
+
- **Zero Gem Dependencies**: Lightweight plugin with minimal runtime dependencies - none besides other than trivy.
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
data/lib/bundler/trivy/config.rb
CHANGED
|
@@ -74,7 +74,7 @@ module Bundler
|
|
|
74
74
|
# config.fail_on_critical? # => true
|
|
75
75
|
def fail_on_critical?
|
|
76
76
|
env_bool("BUNDLER_TRIVY_FAIL_ON_CRITICAL",
|
|
77
|
-
|
|
77
|
+
file_value(%w[fail_on critical], ci_environment?))
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# Determines if the plugin should exit with error on HIGH severity vulnerabilities.
|
|
@@ -86,7 +86,7 @@ module Bundler
|
|
|
86
86
|
# config.fail_on_high? # => true
|
|
87
87
|
def fail_on_high?
|
|
88
88
|
env_bool("BUNDLER_TRIVY_FAIL_ON_HIGH",
|
|
89
|
-
|
|
89
|
+
file_value(%w[fail_on high], false))
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# Determines if the plugin should exit with error on ANY vulnerabilities.
|
|
@@ -111,7 +111,7 @@ module Bundler
|
|
|
111
111
|
# @return [Boolean] true if compact output is enabled
|
|
112
112
|
def compact_output?
|
|
113
113
|
env_bool("BUNDLER_TRIVY_COMPACT",
|
|
114
|
-
|
|
114
|
+
file_value(%w[output compact], ci_environment?))
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
# Determines if output should be in JSON format.
|
|
@@ -160,7 +160,7 @@ module Bundler
|
|
|
160
160
|
# config.trivy_timeout # => 300
|
|
161
161
|
def trivy_timeout
|
|
162
162
|
ENV.fetch("BUNDLER_TRIVY_TIMEOUT",
|
|
163
|
-
|
|
163
|
+
file_value(%w[scanning timeout], 120)).to_i
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
# Returns the list of ignored CVEs from configuration.
|
|
@@ -238,7 +238,8 @@ module Bundler
|
|
|
238
238
|
ignored_cves.each do |ignore|
|
|
239
239
|
if ignore["expires"]
|
|
240
240
|
begin
|
|
241
|
-
Date
|
|
241
|
+
# Handle both string and Date objects
|
|
242
|
+
ignore["expires"].is_a?(Date) ? ignore["expires"] : Date.parse(ignore["expires"].to_s)
|
|
242
243
|
rescue ArgumentError
|
|
243
244
|
errors << "Invalid expiration date for #{ignore["id"]}: #{ignore["expires"]}"
|
|
244
245
|
end
|
|
@@ -284,8 +285,8 @@ module Bundler
|
|
|
284
285
|
end
|
|
285
286
|
|
|
286
287
|
config
|
|
287
|
-
rescue
|
|
288
|
-
Bundler.ui.warn "Failed to load config: #{e.message}"
|
|
288
|
+
rescue => e
|
|
289
|
+
Bundler.ui.warn "Failed to load config (#{config_path}): #{e.message}"
|
|
289
290
|
{}
|
|
290
291
|
end
|
|
291
292
|
|
|
@@ -306,14 +307,16 @@ module Bundler
|
|
|
306
307
|
|
|
307
308
|
def deep_merge(hash1, hash2)
|
|
308
309
|
hash1.merge(hash2) do |_, v1, v2|
|
|
309
|
-
v1.is_a?(Hash) && v2.is_a?(Hash) ? deep_merge(v1, v2) : v2
|
|
310
|
+
(v1.is_a?(Hash) && v2.is_a?(Hash)) ? deep_merge(v1, v2) : v2
|
|
310
311
|
end
|
|
311
312
|
end
|
|
312
313
|
|
|
313
314
|
def expired?(ignore_entry)
|
|
314
315
|
return false unless ignore_entry["expires"]
|
|
315
316
|
|
|
316
|
-
|
|
317
|
+
# Handle both string and Date objects
|
|
318
|
+
expires = ignore_entry["expires"]
|
|
319
|
+
expiration_date = expires.is_a?(Date) ? expires : Date.parse(expires.to_s)
|
|
317
320
|
Date.today > expiration_date
|
|
318
321
|
rescue ArgumentError
|
|
319
322
|
# Handle invalid date format, treat as not expired to be safe
|
data/lib/bundler/trivy/plugin.rb
CHANGED
|
@@ -49,8 +49,12 @@ module Bundler
|
|
|
49
49
|
|
|
50
50
|
# Check if Trivy binary is available in PATH
|
|
51
51
|
unless scanner.trivy_available?
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
begin
|
|
53
|
+
Bundler.ui.warn "Trivy not found, skipping scan"
|
|
54
|
+
Bundler.ui.info "Install: https://trivy.dev/docs/getting-started/installation/"
|
|
55
|
+
rescue
|
|
56
|
+
# Ignore UI errors
|
|
57
|
+
end
|
|
54
58
|
return
|
|
55
59
|
end
|
|
56
60
|
|
|
@@ -64,7 +68,7 @@ module Bundler
|
|
|
64
68
|
|
|
65
69
|
# Exit with error code if vulnerabilities exceed configured thresholds
|
|
66
70
|
handle_exit_code(results, config)
|
|
67
|
-
rescue
|
|
71
|
+
rescue => e
|
|
68
72
|
Bundler.ui.warn "Trivy scan failed: #{e.message}"
|
|
69
73
|
Bundler.ui.debug e.backtrace.join("\n") if ENV["DEBUG"]
|
|
70
74
|
end
|
|
@@ -123,12 +123,16 @@ module Bundler
|
|
|
123
123
|
puts bold("Recommended Actions:")
|
|
124
124
|
puts
|
|
125
125
|
|
|
126
|
-
fixable.group_by(&:package_name).each do |
|
|
126
|
+
fixable.group_by(&:package_name).each do |pkg, vulns|
|
|
127
127
|
# Get all fixed versions from all vulnerabilities for this package
|
|
128
128
|
all_versions = vulns.flat_map(&:fixed_versions).compact.uniq
|
|
129
|
-
# Find the
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
# Find the maximum version that fixes all vulns (safest upgrade path)
|
|
130
|
+
recommended_version = all_versions.max_by { |v| Gem::Version.new(v) } if all_versions.any?
|
|
131
|
+
if recommended_version
|
|
132
|
+
puts " Update #{pkg} to #{recommended_version}: bundle update #{pkg}"
|
|
133
|
+
else
|
|
134
|
+
puts " Update #{pkg}: bundle update #{pkg}"
|
|
135
|
+
end
|
|
132
136
|
end
|
|
133
137
|
|
|
134
138
|
puts
|
|
@@ -167,7 +171,7 @@ module Bundler
|
|
|
167
171
|
end
|
|
168
172
|
|
|
169
173
|
def severity_order(severity)
|
|
170
|
-
{
|
|
174
|
+
{"CRITICAL" => 0, "HIGH" => 1, "MEDIUM" => 2, "LOW" => 3, "UNKNOWN" => 4}[severity] || 99
|
|
171
175
|
end
|
|
172
176
|
|
|
173
177
|
# Color helpers
|
|
@@ -121,7 +121,7 @@ module Bundler
|
|
|
121
121
|
|
|
122
122
|
# Add severity filtering if configured
|
|
123
123
|
severity_filter = @config.severity_filter
|
|
124
|
-
args += ["--severity", severity_filter.join(",")] if severity_filter
|
|
124
|
+
args += ["--severity", severity_filter.join(",")] if severity_filter&.any?
|
|
125
125
|
|
|
126
126
|
args << @project_root
|
|
127
127
|
args
|
|
@@ -99,17 +99,15 @@ module Bundler
|
|
|
99
99
|
return [] unless fixable?
|
|
100
100
|
|
|
101
101
|
fixed_version.split(",").map(&:strip).filter_map do |constraint|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
end
|
|
112
|
-
end.compact
|
|
102
|
+
# Parse as a requirement (e.g., "~> 7.1.5" or ">= 7.1.5.2")
|
|
103
|
+
Gem::Requirement.new(constraint)
|
|
104
|
+
# Extract the version number from the requirement
|
|
105
|
+
# For "~> 7.1.5" -> "7.1.5", ">= 7.1.5.2" -> "7.1.5.2"
|
|
106
|
+
constraint.match(/\d+(?:\.\d+)*/)&.to_s
|
|
107
|
+
rescue ArgumentError
|
|
108
|
+
# If it's not a valid requirement, try to extract version directly
|
|
109
|
+
constraint.match(/\d+(?:\.\d+)*/)&.to_s
|
|
110
|
+
end.compact.reject(&:empty?)
|
|
113
111
|
end
|
|
114
112
|
|
|
115
113
|
# Returns the most applicable fixed version for the installed version.
|
|
@@ -140,12 +138,10 @@ module Bundler
|
|
|
140
138
|
# Return the minimum version in the same series, or the overall minimum
|
|
141
139
|
target_versions = same_series.empty? ? fixed_versions : same_series
|
|
142
140
|
target_versions.min_by do |v|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Gem::Version.new("999.999.999")
|
|
148
|
-
end
|
|
141
|
+
Gem::Version.new(v)
|
|
142
|
+
rescue ArgumentError
|
|
143
|
+
# If version parsing fails, use a very high version to sort it last
|
|
144
|
+
Gem::Version.new("999.999.999")
|
|
149
145
|
end
|
|
150
146
|
rescue ArgumentError
|
|
151
147
|
# If version parsing fails, return the first fixed version
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bundler-trivy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Durable Programming LLC
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '1.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: standard
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: 1.35.1
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 1.35.1
|
|
68
82
|
description: Automatically scans Ruby dependencies for vulnerabilities using Trivy
|
|
69
83
|
after bundle install. Provides configurable security policies, CI/CD integration,
|
|
70
84
|
and comprehensive vulnerability reporting.
|