rubion 0.3.1 → 0.3.2

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: c51023aed1ba275593e8bc5c783d0ee512724b48128ed96d68e433ac7df16f85
4
- data.tar.gz: e31637a3c2be1e60c7e426049d37e6173e5f8a36093a81f53391807538099b4d
3
+ metadata.gz: a34f7102afe1491a751b94e0d11e22fe854f20bb1c1f5a322473447282bd665a
4
+ data.tar.gz: a7dc977d51a43a5657445ee42afc730be67dd2fe6006e35b5153f47ae13fa30d
5
5
  SHA512:
6
- metadata.gz: 4ff1d29b61cac762f306b46751f67c88236575d99323e801021d776fd3b8770685e8821a001bae1c5148d53c4b1884f5dc0952ebbbfef1589b2213ef9f3cad96
7
- data.tar.gz: 23b22a540c176ed00439654959e56f414ebb25fb5c2f8ec0487fad4182d63c4d07ed57be5dda1ffae786f642f277ae86fe604d741b7e7c58fbeee3cbf13bf9a7
6
+ metadata.gz: 13e0b27d669216a58580c02dc8f2e5d26a35a0102e9ac7537bb6d6aa6caea7d42e115b4c12ad6cecc4cdd61add4829a0e549b01578c23d150ce90da4ae859001
7
+ data.tar.gz: f09035851f40e23cdac6f3c594f3f99f4579438ea6421c9007295e1cde0707d689b95675e7435c8da17878defe51bec2ad8427b1ec09fc476727cb026ace9859
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # 🔒 Rubion
1
+ # Rubion
2
2
 
3
3
  **Rubion** is a security and version scanner for Ruby and JavaScript projects. It helps you identify vulnerabilities and outdated dependencies in your Ruby gems and NPM/JavaScript packages.
4
4
 
5
+ <img width="1237" height="671" alt="Screenshot 2025-11-14 at 10 48 12 am" src="https://github.com/user-attachments/assets/a3d93452-c442-416a-9697-de59746e16ad" />
6
+
5
7
  ## Features
6
8
 
7
9
  - 📛 **Gem Vulnerabilities**: Scans for known security vulnerabilities in Ruby gems using `bundle-audit`
@@ -4,8 +4,9 @@ require 'terminal-table'
4
4
 
5
5
  module Rubion
6
6
  class Reporter
7
- def initialize(scan_result)
7
+ def initialize(scan_result, sort_by: nil)
8
8
  @result = scan_result
9
+ @sort_by = sort_by
9
10
  end
10
11
 
11
12
  def report
@@ -36,31 +37,6 @@ module Rubion
36
37
 
37
38
  private
38
39
 
39
- def _print_gem_vulnerabilities
40
- puts "Gem Vulnerabilities:\n\n"
41
-
42
- if @result.gem_vulnerabilities.empty?
43
- puts " ✅ No vulnerabilities found!\n\n"
44
- return
45
- end
46
-
47
- table = Terminal::Table.new do |t|
48
- t.headings = %w[Level Name Version Vulnerability]
49
-
50
- @result.gem_vulnerabilities.each do |vuln|
51
- t.add_row [
52
- severity_with_icon(vuln[:severity]),
53
- vuln[:gem],
54
- vuln[:version],
55
- truncate(vuln[:title], 50)
56
- ]
57
- end
58
- end
59
-
60
- puts table
61
- puts "\n"
62
- end
63
-
64
40
  def print_header
65
41
  # Simplified header
66
42
  puts "\n"
@@ -97,10 +73,14 @@ module Rubion
97
73
  return
98
74
  end
99
75
 
76
+ # Sort if sort_by is specified
77
+ versions = @result.gem_versions.dup
78
+ versions = sort_versions(versions, :gem) if @sort_by
79
+
100
80
  table = Terminal::Table.new do |t|
101
81
  t.headings = ['Name', 'Current', 'Date', 'Latest', 'Date', 'Behind By(Time)', 'Behind By(Versions)']
102
82
 
103
- @result.gem_versions.each do |gem|
83
+ versions.each do |gem|
104
84
  t.add_row [
105
85
  gem[:gem],
106
86
  gem[:current],
@@ -150,10 +130,14 @@ module Rubion
150
130
  return
151
131
  end
152
132
 
133
+ # Sort if sort_by is specified
134
+ versions = @result.package_versions.dup
135
+ versions = sort_versions(versions, :package) if @sort_by
136
+
153
137
  table = Terminal::Table.new do |t|
154
- t.headings = ['Name', 'Current', 'Date', 'Latest', 'Date', 'Behind By', 'Versions']
138
+ t.headings = ['Name', 'Current', 'Date', 'Latest', 'Date', 'Behind By(Time)', 'Behind By(Versions)']
155
139
 
156
- @result.package_versions.each do |pkg|
140
+ versions.each do |pkg|
157
141
  t.add_row [
158
142
  pkg[:package],
159
143
  pkg[:current],
@@ -218,7 +202,7 @@ module Rubion
218
202
  def truncate(text, length = 50)
219
203
  return text if text.length <= length
220
204
 
221
- "#{text[0..length - 3]}..."
205
+ "#{text[0..(length - 3)]}..."
222
206
  end
223
207
 
224
208
  def version_difference(current, latest)
@@ -242,5 +226,104 @@ module Rubion
242
226
  rescue StandardError
243
227
  'unknown'
244
228
  end
229
+
230
+ # Sort versions array based on the specified column
231
+ def sort_versions(versions, name_key)
232
+ return versions unless @sort_by
233
+
234
+ column = @sort_by.strip.downcase
235
+ name_key_sym = name_key # :gem or :package
236
+
237
+ # Normalize column name - default to 'name' if not recognized
238
+ normalized_column = case column
239
+ when 'name', 'current', 'date', 'latest',
240
+ 'behind by(time)', 'behind by time', 'time',
241
+ 'behind by(versions)', 'behind by versions', 'versions'
242
+ column
243
+ else
244
+ 'name' # Default to name sorting
245
+ end
246
+
247
+ versions.sort_by do |item|
248
+ case normalized_column
249
+ when 'name'
250
+ item[name_key_sym].to_s.downcase
251
+ when 'current'
252
+ parse_version_for_sort(item[:current])
253
+ when 'date'
254
+ # Sort by current_date (first Date column)
255
+ parse_date_for_sort(item[:current_date])
256
+ when 'latest'
257
+ parse_version_for_sort(item[:latest])
258
+ when 'behind by(time)', 'behind by time', 'time'
259
+ parse_time_for_sort(item[:time_diff])
260
+ when 'behind by(versions)', 'behind by versions', 'versions'
261
+ parse_version_count_for_sort(item[:version_count])
262
+ end
263
+ end
264
+ end
265
+
266
+ # Parse version string for sorting (handles semantic versions)
267
+ def parse_version_for_sort(version_str)
268
+ return [0, 0, 0, ''] if version_str.nil? || version_str == 'N/A' || version_str == 'unknown'
269
+
270
+ # Handle version strings like "1.2.3", "1.2.3.4", "1.2.3-beta", etc.
271
+ parts = version_str.to_s.split(/[.-]/)
272
+ major = parts[0].to_i
273
+ minor = parts[1].to_i
274
+ patch = parts[2].to_i
275
+ suffix = parts[3..-1].join('') if parts.length > 3
276
+
277
+ [major, minor, patch, suffix || '']
278
+ end
279
+
280
+ # Parse date string for sorting (handles M/D/YYYY format)
281
+ def parse_date_for_sort(date_str)
282
+ return [0, 0, 0] if date_str.nil? || date_str == 'N/A'
283
+
284
+ begin
285
+ parts = date_str.split('/').map(&:to_i)
286
+ return [parts[2] || 0, parts[0] || 0, parts[1] || 0] if parts.length == 3
287
+ rescue StandardError
288
+ # If parsing fails, return a date that sorts last
289
+ end
290
+
291
+ [0, 0, 0]
292
+ end
293
+
294
+ # Parse time difference string for sorting (e.g., "1 year", "3 months", "5 days")
295
+ def parse_time_for_sort(time_str)
296
+ return [0, 0] if time_str.nil? || time_str == 'N/A'
297
+
298
+ time_str = time_str.to_s.downcase.strip
299
+
300
+ # Extract number and unit
301
+ match = time_str.match(/(\d+(?:\.\d+)?)\s*(year|month|day|years|months|days)/)
302
+ return [0, 0] unless match
303
+
304
+ value = match[1].to_f
305
+ unit = match[2].to_s.downcase
306
+
307
+ # Convert to days for comparison
308
+ days = case unit
309
+ when /year/
310
+ value * 365
311
+ when /month/
312
+ value * 30
313
+ when /day/
314
+ value
315
+ else
316
+ 0
317
+ end
318
+
319
+ [days.to_i, value]
320
+ end
321
+
322
+ # Parse version count for sorting
323
+ def parse_version_count_for_sort(count)
324
+ return 0 if count.nil? || count == 'N/A' || count == 'unknown'
325
+
326
+ count.to_i
327
+ end
245
328
  end
246
329
  end
@@ -37,7 +37,7 @@ module Rubion
37
37
  @result
38
38
  end
39
39
 
40
- def scan_incremental(options = { gems: true, packages: true })
40
+ def scan_incremental(options = { gems: true, packages: true, sort_by: nil })
41
41
  puts "🔍 Scanning project at: #{@project_path}\n\n"
42
42
 
43
43
  # Scan and display Ruby gems first (if enabled)
@@ -46,7 +46,7 @@ module Rubion
46
46
 
47
47
  # Print gem results immediately
48
48
  puts "\n"
49
- reporter = Reporter.new(@result)
49
+ reporter = Reporter.new(@result, sort_by: options[:sort_by])
50
50
  reporter.print_gem_vulnerabilities
51
51
  reporter.print_gem_versions
52
52
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubion
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.2"
5
5
  end
6
6
 
data/lib/rubion.rb CHANGED
@@ -28,7 +28,7 @@ module Rubion
28
28
  end
29
29
 
30
30
  def self.parse_scan_options(args)
31
- options = { gems: true, packages: true }
31
+ options = { gems: true, packages: true, sort_by: nil }
32
32
 
33
33
  # Check for --gems-only or --packages-only flags
34
34
  if args.include?('--gems-only') || args.include?('-g')
@@ -43,20 +43,28 @@ module Rubion
43
43
  options[:packages] = args.include?('--packages')
44
44
  end
45
45
 
46
+ # Parse --sort-by or -s option
47
+ sort_index = args.index('--sort-by') || args.index('-s')
48
+ if sort_index && args[sort_index + 1]
49
+ options[:sort_by] = args[sort_index + 1]
50
+ end
51
+
46
52
  options
47
53
  end
48
54
 
49
- def self.scan(options = { gems: true, packages: true })
55
+ def self.scan(options = { gems: true, packages: true, sort_by: nil })
50
56
  project_path = Dir.pwd
51
57
 
52
58
  scanner = Scanner.new(project_path: project_path)
53
59
  result = scanner.scan_incremental(options)
54
60
 
55
61
  # Results are already printed incrementally based on options
56
- reporter = Reporter.new(result)
57
-
58
- # Only print package results if packages were scanned
62
+ # Package results are printed in scan_incremental, but we need to ensure
63
+ # they use the same reporter instance with sort_by
64
+ # Actually, scan_incremental handles gem printing, but package printing
65
+ # happens here, so we need a reporter for packages
59
66
  if options[:packages]
67
+ reporter = Reporter.new(result, sort_by: options[:sort_by])
60
68
  reporter.print_package_vulnerabilities
61
69
  reporter.print_package_versions
62
70
  end
@@ -76,6 +84,7 @@ module Rubion
76
84
  --gems, --gem, -g Scan only Ruby gems (skip NPM packages)
77
85
  --packages, --npm, -p Scan only NPM packages (skip Ruby gems)
78
86
  --all, -a Scan both gems and packages (default)
87
+ --sort-by COLUMN, -s COLUMN Sort results by column (Name, Current, Date, Latest, Behind By(Time), Behind By(Versions))
79
88
 
80
89
  DESCRIPTION:
81
90
  Rubion scans your project for:
@@ -101,6 +110,12 @@ module Rubion
101
110
  # Scan only NPM packages
102
111
  rubion scan --packages
103
112
 
113
+ # Sort by name
114
+ rubion scan --sort-by Name
115
+
116
+ # Sort by versions behind
117
+ rubion scan -s "Behind By(Versions)"
118
+
104
119
  # Get help
105
120
  rubion help
106
121
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - bipashant