rubion 0.3.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/Gemfile +11 -0
- data/LICENSE +22 -0
- data/README.md +273 -0
- data/bin/rubion +7 -0
- data/lib/rubion/reporter.rb +246 -0
- data/lib/rubion/scanner.rb +583 -0
- data/lib/rubion/version.rb +6 -0
- data/lib/rubion.rb +117 -0
- data/rubion.gemspec +36 -0
- metadata +112 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f3dc20ad2e0d8a10c9819577c5370327e860d1406b866fa02504e472dbb1e673
|
|
4
|
+
data.tar.gz: b7954923cc22c872f7a20520db5bf2496af0615886978d2701188357b1e3cdf2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c8997bc21f73e51e7e904e8372fd779d85f5b162ff0d7b7187ce4136571343913d6362d61a2cb2839d3c8333f91b3af8724192a6b7bff9ae361c357975d8dce6
|
|
7
|
+
data.tar.gz: 8e18d1257ef3cc883c7dba88355c3c7928c60f31bb17d20135b19954ad4ac055b2aeb21338d9453156959330ad3432aa36ab2e7772c315ec9bc8bb81a9946ab2
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 [Your Name]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# 🔒 Rubion
|
|
2
|
+
|
|
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 packages.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📛 **Gem Vulnerabilities**: Scans for known security vulnerabilities in Ruby gems using `bundle-audit`
|
|
8
|
+
- 📦 **Gem Versions**: Identifies outdated Ruby gems with release dates and version counts
|
|
9
|
+
- 📛 **Package Vulnerabilities**: Scans for known security vulnerabilities in NPM packages using `npm audit`
|
|
10
|
+
- 📦 **Package Versions**: Identifies outdated NPM packages with release dates and version counts
|
|
11
|
+
- 📊 **Beautiful Reports**: Organized table output with severity icons (🔴 Critical, 🟠 High, 🟡 Medium, 🟢 Low, ⚪ Unknown)
|
|
12
|
+
- 🚀 **Fast & Efficient**: Parallel API processing (10 concurrent threads) for quick results
|
|
13
|
+
- ⚡ **Incremental Output**: Shows gem results immediately, then scans packages
|
|
14
|
+
- 📅 **Release Dates**: Fetches actual release dates from RubyGems.org and NPM registry
|
|
15
|
+
- 🔢 **Version Analysis**: Shows how many versions behind and time difference
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Install from RubyGems (when published)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gem install rubion
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Install from source
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/yourusername/rubion.git
|
|
29
|
+
cd rubion
|
|
30
|
+
bundle install
|
|
31
|
+
rake install_local
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Scan your project
|
|
37
|
+
|
|
38
|
+
Navigate to your project directory and run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
rubion scan
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This will scan your project for:
|
|
45
|
+
- Ruby gem vulnerabilities (if `Gemfile.lock` exists)
|
|
46
|
+
- Outdated Ruby gems with release dates
|
|
47
|
+
- NPM package vulnerabilities (if `package.json` exists)
|
|
48
|
+
- Outdated NPM packages with release dates
|
|
49
|
+
|
|
50
|
+
### Scan options
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Scan only Ruby gems (skip NPM packages)
|
|
54
|
+
rubion scan --gems-only
|
|
55
|
+
# or
|
|
56
|
+
rubion scan -g
|
|
57
|
+
|
|
58
|
+
# Scan only NPM packages (skip Ruby gems)
|
|
59
|
+
rubion scan --packages-only
|
|
60
|
+
# or
|
|
61
|
+
rubion scan -p
|
|
62
|
+
|
|
63
|
+
# Scan both (default)
|
|
64
|
+
rubion scan
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### View help
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
rubion help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Check version
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
rubion version
|
|
77
|
+
# or
|
|
78
|
+
rubion -v
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Output Example
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
🔍 Scanning project at: /path/to/project
|
|
85
|
+
|
|
86
|
+
📦 Checking Ruby gems... 139/139 ✓
|
|
87
|
+
|
|
88
|
+
Gem Vulnerabilities:
|
|
89
|
+
|
|
90
|
+
+----------+--------+---------+------------------------------------------+
|
|
91
|
+
| Level | Name | Version | Vulnerability |
|
|
92
|
+
+----------+--------+---------+------------------------------------------+
|
|
93
|
+
| 🔴 Critical | rexml | 3.4.1 | REXML has DoS condition when parsing... |
|
|
94
|
+
| 🟠 High | rack | 2.0.8 | Denial of Service vulnerability |
|
|
95
|
+
+----------+--------+---------+------------------------------------------+
|
|
96
|
+
|
|
97
|
+
Gem Versions:
|
|
98
|
+
|
|
99
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
100
|
+
| Name | Current | Date | Latest | Date | Behind By | Versions |
|
|
101
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
102
|
+
| sidekiq | 7.30 | 3/5/2024 | 8.1 | 11/11/2025| 1 year | 15 |
|
|
103
|
+
| fastimage| 2.2.7 | 2/2/2025 | 2.3.2 | 9/9/2025 | 7 months | 3 |
|
|
104
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
105
|
+
|
|
106
|
+
📦 Checking NPM packages... 45/45 ✓
|
|
107
|
+
|
|
108
|
+
Package Vulnerabilities:
|
|
109
|
+
|
|
110
|
+
+----------+--------+---------+------------------------------------------+
|
|
111
|
+
| Level | Name | Version | Vulnerability |
|
|
112
|
+
+----------+--------+---------+------------------------------------------+
|
|
113
|
+
| 🟠 High | moment | 1.2.3 | Wrong timezone date calculation |
|
|
114
|
+
+----------+--------+---------+------------------------------------------+
|
|
115
|
+
|
|
116
|
+
Package Versions:
|
|
117
|
+
|
|
118
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
119
|
+
| Name | Current | Date | Latest | Date | Behind By | Versions |
|
|
120
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
121
|
+
| jquery | 3.7.1 | 4/5/2024 | 3.9.1 | 10/11/2025| 1 year | 8 |
|
|
122
|
+
+----------+---------+-----------+---------+-----------+-----------+----------+
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Requirements
|
|
126
|
+
|
|
127
|
+
- Ruby 2.6 or higher
|
|
128
|
+
- Bundler (for Ruby gem scanning)
|
|
129
|
+
- NPM (optional, for NPM package scanning)
|
|
130
|
+
- `bundler-audit` (optional, for enhanced gem vulnerability detection)
|
|
131
|
+
|
|
132
|
+
### Installing bundler-audit (recommended)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
gem install bundler-audit
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Note:** Without `bundler-audit`, gem vulnerability scanning will be skipped.
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt.
|
|
143
|
+
|
|
144
|
+
### Running tests
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
rake spec
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Running RuboCop
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
rake rubocop
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Building the gem
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
gem build rubion.gemspec
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Installing locally
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
rake install_local
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## How It Works
|
|
169
|
+
|
|
170
|
+
Rubion uses a modular architecture:
|
|
171
|
+
|
|
172
|
+
1. **Scanner** (`lib/rubion/scanner.rb`): Executes various commands to scan for vulnerabilities and outdated versions
|
|
173
|
+
- `bundle-audit check` for gem vulnerabilities
|
|
174
|
+
- `bundle outdated --parseable` for gem versions
|
|
175
|
+
- `npm audit --json` for package vulnerabilities
|
|
176
|
+
- `npm outdated --json` for package versions
|
|
177
|
+
- Fetches release dates and version data from RubyGems.org and NPM registry APIs
|
|
178
|
+
- Uses parallel processing (10 concurrent threads) for fast API calls
|
|
179
|
+
|
|
180
|
+
2. **Reporter** (`lib/rubion/reporter.rb`): Formats scan results into beautiful terminal tables using `terminal-table`
|
|
181
|
+
- Adds severity icons (🔴 🟠 🟡 🟢 ⚪)
|
|
182
|
+
- Formats dates, time differences, and version counts
|
|
183
|
+
- Supports incremental output (gems first, then packages)
|
|
184
|
+
|
|
185
|
+
3. **CLI** (`lib/rubion.rb`): Provides the command-line interface
|
|
186
|
+
- Parses command-line options (`--gems-only`, `--packages-only`)
|
|
187
|
+
- Coordinates scanning and reporting
|
|
188
|
+
|
|
189
|
+
For detailed information about data collection and mapping, see [HOW_IT_WORKS.md](HOW_IT_WORKS.md).
|
|
190
|
+
|
|
191
|
+
## Extending Rubion
|
|
192
|
+
|
|
193
|
+
Rubion is designed to be easily extensible. To add new scanners:
|
|
194
|
+
|
|
195
|
+
1. Add a new method in `lib/rubion/scanner.rb`
|
|
196
|
+
2. Add a corresponding report method in `lib/rubion/reporter.rb`
|
|
197
|
+
3. Update the scan flow in `Scanner#scan`
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
# In scanner.rb
|
|
203
|
+
def scan_python_packages
|
|
204
|
+
# Your scanning logic here
|
|
205
|
+
@result.python_vulnerabilities = check_pip_vulnerabilities
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# In reporter.rb
|
|
209
|
+
def print_python_vulnerabilities
|
|
210
|
+
# Your reporting logic here
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Contributing
|
|
215
|
+
|
|
216
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/rubion.
|
|
217
|
+
|
|
218
|
+
1. Fork it
|
|
219
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
|
220
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
221
|
+
4. Push to the branch (`git push origin feature/my-new-feature`)
|
|
222
|
+
5. Create new Pull Request
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
227
|
+
|
|
228
|
+
## Code of Conduct
|
|
229
|
+
|
|
230
|
+
Everyone interacting in the Rubion project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
|
|
231
|
+
|
|
232
|
+
## Support
|
|
233
|
+
|
|
234
|
+
If you have any questions or need help, please:
|
|
235
|
+
- Open an issue on GitHub
|
|
236
|
+
- Check the documentation
|
|
237
|
+
- Contact the maintainers
|
|
238
|
+
|
|
239
|
+
## Performance
|
|
240
|
+
|
|
241
|
+
Rubion is optimized for speed:
|
|
242
|
+
|
|
243
|
+
- **Parallel API Processing**: Uses 10 concurrent threads to fetch version data from RubyGems.org and NPM registry
|
|
244
|
+
- **Single API Call Per Package**: Fetches all necessary data (dates, version list) in one request
|
|
245
|
+
- **Incremental Output**: Shows gem results immediately, then scans packages (better UX)
|
|
246
|
+
- **Progress Indicators**: Shows real-time progress like "Checking Ruby gems... 10/54"
|
|
247
|
+
|
|
248
|
+
Typical scan times:
|
|
249
|
+
- Gems only: ~4-5 seconds (for ~140 gems)
|
|
250
|
+
- Packages only: ~3-4 seconds (for ~50 packages)
|
|
251
|
+
- Both: ~7-9 seconds total
|
|
252
|
+
|
|
253
|
+
## Roadmap
|
|
254
|
+
|
|
255
|
+
Future features planned:
|
|
256
|
+
- [ ] Sorting options (by severity, name, date, etc.)
|
|
257
|
+
- [ ] Filtering options (by severity, outdated threshold, etc.)
|
|
258
|
+
- [ ] Export formats (JSON, CSV, HTML)
|
|
259
|
+
- [ ] Summary statistics
|
|
260
|
+
- [ ] Update command suggestions
|
|
261
|
+
- [ ] Support for Python (pip) packages
|
|
262
|
+
- [ ] Support for PHP (composer) packages
|
|
263
|
+
- [ ] Support for Go modules
|
|
264
|
+
- [ ] CI/CD integration flags
|
|
265
|
+
- [ ] Configurable severity thresholds
|
|
266
|
+
- [ ] Auto-fix suggestions
|
|
267
|
+
- [ ] Historical tracking of vulnerabilities
|
|
268
|
+
|
|
269
|
+
## Acknowledgments
|
|
270
|
+
|
|
271
|
+
- Built with [terminal-table](https://github.com/tj/terminal-table)
|
|
272
|
+
- Inspired by tools like `bundle-audit` and `npm audit`
|
|
273
|
+
|
data/bin/rubion
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'terminal-table'
|
|
4
|
+
|
|
5
|
+
module Rubion
|
|
6
|
+
class Reporter
|
|
7
|
+
def initialize(scan_result)
|
|
8
|
+
@result = scan_result
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def report
|
|
12
|
+
print_header
|
|
13
|
+
_print_gem_vulnerabilities
|
|
14
|
+
_print_gem_versions
|
|
15
|
+
_print_package_vulnerabilities
|
|
16
|
+
_print_package_versions
|
|
17
|
+
print_summary
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Public methods for incremental reporting
|
|
21
|
+
def print_gem_vulnerabilities
|
|
22
|
+
_print_gem_vulnerabilities
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def print_gem_versions
|
|
26
|
+
_print_gem_versions
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def print_package_vulnerabilities
|
|
30
|
+
_print_package_vulnerabilities
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def print_package_versions
|
|
34
|
+
_print_package_versions
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
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
|
+
def print_header
|
|
65
|
+
# Simplified header
|
|
66
|
+
puts "\n"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def _print_gem_vulnerabilities
|
|
70
|
+
if @result.gem_vulnerabilities.empty?
|
|
71
|
+
puts " ✅ No vulnerabilities found!\n\n"
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
table = Terminal::Table.new do |t|
|
|
76
|
+
t.headings = %w[Level Name Version Vulnerability]
|
|
77
|
+
|
|
78
|
+
@result.gem_vulnerabilities.each do |vuln|
|
|
79
|
+
t.add_row [
|
|
80
|
+
severity_with_icon(vuln[:severity]),
|
|
81
|
+
vuln[:gem],
|
|
82
|
+
vuln[:version],
|
|
83
|
+
truncate(vuln[:title], 50)
|
|
84
|
+
]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
puts table
|
|
89
|
+
puts "\n"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def _print_gem_versions
|
|
93
|
+
puts "Gem Versions:\n\n"
|
|
94
|
+
|
|
95
|
+
if @result.gem_versions.empty?
|
|
96
|
+
puts " ✅ All gems are up to date!\n\n"
|
|
97
|
+
return
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
table = Terminal::Table.new do |t|
|
|
101
|
+
t.headings = ['Name', 'Current', 'Date', 'Latest', 'Date', 'Behind By(Time)', 'Behind By(Versions)']
|
|
102
|
+
|
|
103
|
+
@result.gem_versions.each do |gem|
|
|
104
|
+
t.add_row [
|
|
105
|
+
gem[:gem],
|
|
106
|
+
gem[:current],
|
|
107
|
+
gem[:current_date] || 'N/A',
|
|
108
|
+
gem[:latest],
|
|
109
|
+
gem[:latest_date] || 'N/A',
|
|
110
|
+
gem[:time_diff] || 'N/A',
|
|
111
|
+
gem[:version_count] || 'N/A'
|
|
112
|
+
]
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
puts table
|
|
117
|
+
puts "\n"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def _print_package_vulnerabilities
|
|
121
|
+
puts "Package Vulnerabilities:\n\n"
|
|
122
|
+
|
|
123
|
+
if @result.package_vulnerabilities.empty?
|
|
124
|
+
puts " ✅ No vulnerabilities found!\n\n"
|
|
125
|
+
return
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
table = Terminal::Table.new do |t|
|
|
129
|
+
t.headings = %w[Level Name Version Vulnerability]
|
|
130
|
+
|
|
131
|
+
@result.package_vulnerabilities.each do |vuln|
|
|
132
|
+
t.add_row [
|
|
133
|
+
severity_with_icon(vuln[:severity]),
|
|
134
|
+
vuln[:package],
|
|
135
|
+
vuln[:version],
|
|
136
|
+
truncate(vuln[:title], 50)
|
|
137
|
+
]
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
puts table
|
|
142
|
+
puts "\n"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def _print_package_versions
|
|
146
|
+
puts "Package Versions:\n\n"
|
|
147
|
+
|
|
148
|
+
if @result.package_versions.empty?
|
|
149
|
+
puts " ✅ All packages are up to date!\n\n"
|
|
150
|
+
return
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
table = Terminal::Table.new do |t|
|
|
154
|
+
t.headings = ['Name', 'Current', 'Date', 'Latest', 'Date', 'Behind By', 'Versions']
|
|
155
|
+
|
|
156
|
+
@result.package_versions.each do |pkg|
|
|
157
|
+
t.add_row [
|
|
158
|
+
pkg[:package],
|
|
159
|
+
pkg[:current],
|
|
160
|
+
pkg[:current_date] || 'N/A',
|
|
161
|
+
pkg[:latest],
|
|
162
|
+
pkg[:latest_date] || 'N/A',
|
|
163
|
+
pkg[:time_diff] || 'N/A',
|
|
164
|
+
pkg[:version_count] || 'N/A'
|
|
165
|
+
]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
puts table
|
|
170
|
+
puts "\n"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def print_summary
|
|
174
|
+
# Minimal summary at the end
|
|
175
|
+
puts "\n"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Helpers
|
|
179
|
+
|
|
180
|
+
def severity_with_icon(severity)
|
|
181
|
+
severity_str = severity.to_s.capitalize
|
|
182
|
+
|
|
183
|
+
case severity.to_s.downcase
|
|
184
|
+
when 'critical'
|
|
185
|
+
"🔴 #{severity_str}"
|
|
186
|
+
when 'high'
|
|
187
|
+
"🟠 #{severity_str}"
|
|
188
|
+
when 'medium', 'moderate'
|
|
189
|
+
"🟡 #{severity_str}"
|
|
190
|
+
when 'low'
|
|
191
|
+
"🟢 #{severity_str}"
|
|
192
|
+
when 'unknown'
|
|
193
|
+
"⚪ #{severity_str}"
|
|
194
|
+
else
|
|
195
|
+
severity_str
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def colorize_severity(severity)
|
|
200
|
+
case severity.to_s.downcase
|
|
201
|
+
when 'critical'
|
|
202
|
+
"🔴 #{severity}"
|
|
203
|
+
when 'high'
|
|
204
|
+
"🟠 #{severity}"
|
|
205
|
+
when 'medium', 'moderate'
|
|
206
|
+
"🟡 #{severity}"
|
|
207
|
+
when 'low'
|
|
208
|
+
"🟢 #{severity}"
|
|
209
|
+
else
|
|
210
|
+
severity
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def colorize_count(count)
|
|
215
|
+
count > 0 ? "🔴 #{count}" : "✅ #{count}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def truncate(text, length = 50)
|
|
219
|
+
return text if text.length <= length
|
|
220
|
+
|
|
221
|
+
"#{text[0..length - 3]}..."
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def version_difference(current, latest)
|
|
225
|
+
# Simple version difference calculation
|
|
226
|
+
current_parts = current.split('.').map(&:to_i)
|
|
227
|
+
latest_parts = latest.split('.').map(&:to_i)
|
|
228
|
+
|
|
229
|
+
major_diff = (latest_parts[0] || 0) - (current_parts[0] || 0)
|
|
230
|
+
minor_diff = (latest_parts[1] || 0) - (current_parts[1] || 0)
|
|
231
|
+
patch_diff = (latest_parts[2] || 0) - (current_parts[2] || 0)
|
|
232
|
+
|
|
233
|
+
if major_diff > 0
|
|
234
|
+
"#{major_diff} major"
|
|
235
|
+
elsif minor_diff > 0
|
|
236
|
+
"#{minor_diff} minor"
|
|
237
|
+
elsif patch_diff > 0
|
|
238
|
+
"#{patch_diff} patch"
|
|
239
|
+
else
|
|
240
|
+
'up to date'
|
|
241
|
+
end
|
|
242
|
+
rescue StandardError
|
|
243
|
+
'unknown'
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|