rubion 0.3.15 → 0.3.17
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/lib/rubion/scanner.rb +77 -30
- data/lib/rubion/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d382653589bad6b28b68444b231efafa582f375cf1d4c7284d8df5faae04d50
|
|
4
|
+
data.tar.gz: 3edfba9269ed3024943544887422101b7512cd4309c5e689fbd6f8a7cf655a60
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a5f3c72e3d1f257c426e0df25efb3b1ae62751527324bd5a8991986dd12aa6652cb0ca81aecd2941c3b00a19a5ceff090d1718ff5d540e59c0ddbc509707dd73
|
|
7
|
+
data.tar.gz: bc17b9ebd3c5081cb040deba4358eae42f4a941169fa7a5db919ea9ef92065dfa33fcb11dcc0a2925e58a62ebbb9ea4dad3364c69ff46133b7a2f79447885503
|
data/lib/rubion/scanner.rb
CHANGED
|
@@ -106,8 +106,10 @@ module Rubion
|
|
|
106
106
|
# Exit code 0 means no vulnerabilities found
|
|
107
107
|
# Any other exit code or error means the command failed
|
|
108
108
|
if status.exitstatus.nil? || status.exitstatus == 127 || stderr.include?('command not found') || stdout.include?('command not found')
|
|
109
|
-
# Command not found -
|
|
110
|
-
|
|
109
|
+
# Command not found - show friendly message and skip vulnerability check
|
|
110
|
+
puts "\n ℹ️ bundle-audit is not installed. Skipping gem vulnerability check."
|
|
111
|
+
puts " To enable vulnerability scanning, install it with: gem install bundler-audit\n"
|
|
112
|
+
@result.gem_vulnerabilities = []
|
|
111
113
|
elsif status.exitstatus == 1 || status.success? || (!stdout.empty? && (stdout.include?('vulnerabilities found') || stdout.include?('Name:')))
|
|
112
114
|
# Exit code 1 (vulnerabilities found) or 0 (no vulnerabilities) - parse output
|
|
113
115
|
# Also try to parse if output looks valid even if exit code is unexpected
|
|
@@ -120,37 +122,20 @@ module Rubion
|
|
|
120
122
|
end
|
|
121
123
|
end
|
|
122
124
|
|
|
123
|
-
def install_bundler_audit_and_retry
|
|
124
|
-
puts "\n ⚠️ bundle-audit is not installed."
|
|
125
|
-
print ' Attempting to install bundler-audit... '
|
|
126
|
-
$stdout.flush
|
|
127
|
-
|
|
128
|
-
_install_stdout, install_stderr, install_status = Open3.capture3('gem install bundler-audit 2>&1')
|
|
129
|
-
|
|
130
|
-
if install_status.success?
|
|
131
|
-
puts "✓ Successfully installed bundler-audit\n"
|
|
132
|
-
puts " Retrying gem vulnerability check...\n\n"
|
|
133
|
-
# Retry the check after installation
|
|
134
|
-
check_gem_vulnerabilities
|
|
135
|
-
else
|
|
136
|
-
puts '✗ Failed to install bundler-audit'
|
|
137
|
-
raise "bundle-audit is not installed and automatic installation failed.\n" \
|
|
138
|
-
"Please install it manually by running: gem install bundler-audit\n" \
|
|
139
|
-
"Installation error: #{install_stderr}"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
125
|
def check_gem_versions
|
|
144
126
|
stdout, stderr, status = Open3.capture3('bundle outdated --parseable', chdir: @project_path)
|
|
145
127
|
|
|
146
|
-
|
|
147
|
-
|
|
128
|
+
# bundle outdated returns exit code 1 when outdated gems are found (expected behavior)
|
|
129
|
+
# Exit code 0 means no outdated gems or command succeeded
|
|
130
|
+
# Exit code 1 means outdated gems found - this is success, not an error
|
|
131
|
+
if status.success? || status.exitstatus == 1
|
|
132
|
+
# Command succeeded or outdated gems found - parse output
|
|
148
133
|
parse_bundle_outdated_output(stdout)
|
|
149
134
|
elsif status.exitstatus.nil?
|
|
150
135
|
# Command not found or failed to execute
|
|
151
136
|
raise "bundle outdated command failed or is not available. Error: #{stderr}"
|
|
152
137
|
else
|
|
153
|
-
# Command failed with non-zero exit code
|
|
138
|
+
# Command failed with unexpected non-zero exit code
|
|
154
139
|
raise "bundle outdated failed with exit code #{status.exitstatus}. Output: #{stdout}#{unless stderr.empty?
|
|
155
140
|
"\nError: #{stderr}"
|
|
156
141
|
end}"
|
|
@@ -166,16 +151,22 @@ module Rubion
|
|
|
166
151
|
if status.exitstatus.nil?
|
|
167
152
|
# Command not found or failed to execute
|
|
168
153
|
raise "#{@package_manager} audit command failed or is not available. Error: #{stderr}"
|
|
169
|
-
elsif !status.success? && status.exitstatus != 1
|
|
170
|
-
# Exit code 1 is expected when vulnerabilities are found
|
|
154
|
+
elsif !status.success? && status.exitstatus != 1 && status.exitstatus != 4
|
|
155
|
+
# Exit code 1 (npm) or 4 (yarn) is expected when vulnerabilities are found
|
|
156
|
+
# Other non-zero codes are errors
|
|
171
157
|
raise "#{@package_manager} audit failed with exit code #{status.exitstatus}. Output: #{stdout}#{unless stderr.empty?
|
|
172
158
|
"\nError: #{stderr}"
|
|
173
159
|
end}"
|
|
174
160
|
end
|
|
175
161
|
|
|
176
162
|
begin
|
|
177
|
-
|
|
178
|
-
|
|
163
|
+
# Yarn audit outputs JSON line by line, need to parse each line
|
|
164
|
+
if @package_manager == 'yarn'
|
|
165
|
+
parse_yarn_audit_output(stdout)
|
|
166
|
+
else
|
|
167
|
+
data = JSON.parse(stdout)
|
|
168
|
+
parse_npm_audit_output(data)
|
|
169
|
+
end
|
|
179
170
|
rescue JSON::ParserError => e
|
|
180
171
|
raise "Failed to parse #{@package_manager} audit JSON output: #{e.message}. Raw output: #{stdout}"
|
|
181
172
|
end
|
|
@@ -382,6 +373,55 @@ module Rubion
|
|
|
382
373
|
@result.package_vulnerabilities = vulnerabilities
|
|
383
374
|
end
|
|
384
375
|
|
|
376
|
+
def parse_yarn_audit_output(output)
|
|
377
|
+
vulnerabilities = []
|
|
378
|
+
seen_advisories = {}
|
|
379
|
+
|
|
380
|
+
# Yarn audit outputs JSON line by line
|
|
381
|
+
output.each_line do |line|
|
|
382
|
+
next if line.strip.empty?
|
|
383
|
+
|
|
384
|
+
begin
|
|
385
|
+
json_obj = JSON.parse(line)
|
|
386
|
+
next unless json_obj.is_a?(Hash)
|
|
387
|
+
|
|
388
|
+
# Parse auditAdvisory type
|
|
389
|
+
if json_obj['type'] == 'auditAdvisory' && json_obj['data'] && json_obj['data']['advisory']
|
|
390
|
+
advisory = json_obj['data']['advisory']
|
|
391
|
+
advisory_id = advisory['id']
|
|
392
|
+
|
|
393
|
+
# Skip if we've already seen this advisory
|
|
394
|
+
next if seen_advisories[advisory_id]
|
|
395
|
+
|
|
396
|
+
seen_advisories[advisory_id] = true
|
|
397
|
+
|
|
398
|
+
# Extract package name and version from findings
|
|
399
|
+
if advisory['findings'] && advisory['findings'].is_a?(Array) && advisory['findings'].first
|
|
400
|
+
finding = advisory['findings'].first
|
|
401
|
+
version = finding['version'] || 'unknown'
|
|
402
|
+
else
|
|
403
|
+
version = 'unknown'
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Get severity (yarn uses lowercase)
|
|
407
|
+
severity = (advisory['severity'] || 'unknown').downcase
|
|
408
|
+
|
|
409
|
+
vulnerabilities << {
|
|
410
|
+
package: advisory['module_name'] || 'unknown',
|
|
411
|
+
version: version,
|
|
412
|
+
severity: severity,
|
|
413
|
+
title: advisory['title'] || advisory['overview'] || 'Vulnerability detected'
|
|
414
|
+
}
|
|
415
|
+
end
|
|
416
|
+
rescue JSON::ParserError
|
|
417
|
+
# Skip invalid JSON lines
|
|
418
|
+
next
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
@result.package_vulnerabilities = vulnerabilities
|
|
423
|
+
end
|
|
424
|
+
|
|
385
425
|
def parse_npm_outdated_output(data)
|
|
386
426
|
versions = []
|
|
387
427
|
|
|
@@ -807,7 +847,14 @@ module Rubion
|
|
|
807
847
|
puts "\n Both npm and yarn are available. Which would you like to use?"
|
|
808
848
|
print " Enter 'n' for npm or 'y' for yarn (default: npm): "
|
|
809
849
|
|
|
810
|
-
|
|
850
|
+
input = $stdin.gets
|
|
851
|
+
if input.nil?
|
|
852
|
+
# stdin not available (e.g., running through bundle exec in non-interactive mode)
|
|
853
|
+
puts " (stdin not available, using npm as default)\n"
|
|
854
|
+
return 'npm'
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
choice = input.chomp.strip.downcase
|
|
811
858
|
|
|
812
859
|
if choice.empty? || choice == 'n' || choice == 'npm'
|
|
813
860
|
'npm'
|
data/lib/rubion/version.rb
CHANGED