bundle-patch 0.3.0 β 0.4.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 +4 -4
- data/README.md +102 -29
- data/lib/bundle/patch/version.rb +1 -1
- data/lib/bundle/patch.rb +50 -30
- metadata +16 -3
- data/lib/bundle/patch/bundler_audit_installer.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0903e6a807f6bdab47f3b7b4872424fd5bad54c4c84b66033c2d398f793dbb5
|
4
|
+
data.tar.gz: b9956c73baf2f0fe592b348af500641e00f540faeb00c91f00d35fe5cfa4c432
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bb2038b986f0552bfaa5b7c3ec5f205ba590ecd9e3940270e535a88ab790a9a4374ce6c24298f0024dc6e96c53eecbc9a99d6608e662386e960cc2e64b88d7b
|
7
|
+
data.tar.gz: 1cf395cc171ff075e7665db75d2196638e2cdb17867c6cdf68c565ac9e00419afd538f5ac7739d63e348143a5d36af840a6a27768e08ce38735e836461ca7107
|
data/README.md
CHANGED
@@ -14,17 +14,56 @@ It parses audit output, finds the **best patchable version** for each vulnerable
|
|
14
14
|
- Supports patch/minor/major upgrade strategies
|
15
15
|
- Handles indirect dependencies by explicitly adding them
|
16
16
|
- Has a dry-run mode
|
17
|
+
- Creates backup of your Gemfile before changes
|
17
18
|
|
18
19
|
---
|
19
20
|
|
20
|
-
##
|
21
|
+
## π Requirements
|
22
|
+
|
23
|
+
- Ruby 2.6 or later
|
24
|
+
- Bundler installed
|
25
|
+
- bundler-audit installed (will be installed automatically if missing)
|
26
|
+
|
27
|
+
---
|
28
|
+
|
29
|
+
## π¦ Installation
|
30
|
+
|
31
|
+
Add this gem to your system:
|
21
32
|
|
22
33
|
```bash
|
23
|
-
bundle-patch
|
34
|
+
gem install bundle-patch
|
24
35
|
```
|
25
36
|
|
26
|
-
|
37
|
+
Or add it to your project's Gemfile for use in development:
|
27
38
|
|
39
|
+
```ruby
|
40
|
+
# Gemfile
|
41
|
+
group :development do
|
42
|
+
gem 'bundle-patch'
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
And then:
|
47
|
+
|
48
|
+
```bash
|
49
|
+
bundle install
|
50
|
+
```
|
51
|
+
|
52
|
+
---
|
53
|
+
|
54
|
+
## π‘ Examples
|
55
|
+
|
56
|
+
### Basic Usage
|
57
|
+
```bash
|
58
|
+
bundle-patch
|
59
|
+
```
|
60
|
+
This will run in patch mode (default) and update only patch versions.
|
61
|
+
|
62
|
+
### Minor Version Updates
|
63
|
+
```bash
|
64
|
+
bundle-patch --mode=minor
|
65
|
+
```
|
66
|
+
Example output:
|
28
67
|
```
|
29
68
|
π Running `bundle-audit check --format json`...
|
30
69
|
π Found 2 vulnerabilities:
|
@@ -40,43 +79,77 @@ Example output
|
|
40
79
|
β
bundle install completed successfully
|
41
80
|
```
|
42
81
|
|
43
|
-
|
44
|
-
|
45
|
-
| Option | Description |
|
46
|
-
| ----------------------- | ------------------------------------------------------------------------- |
|
47
|
-
| `--mode=patch` | Only allow patch-level updates (default) |
|
48
|
-
| `--mode=minor` | Allow minor version updates |
|
49
|
-
| `--mode=all` | Allow all updates including major versions |
|
50
|
-
| `--dry-run` | Only print what would be changed, donβt touch the Gemfile or install gems |
|
51
|
-
| `--skip_bundle_install` | Modify the Gemfile, but skip `bundle install` |
|
52
|
-
|
53
|
-
## π¦ Installation
|
54
|
-
|
55
|
-
Add this gem to your system:
|
56
|
-
|
82
|
+
### Dry Run Mode
|
57
83
|
```bash
|
58
|
-
|
84
|
+
bundle-patch --dry-run
|
59
85
|
```
|
86
|
+
This will show what would be changed without making any actual changes.
|
60
87
|
|
61
|
-
|
88
|
+
### Skip Bundle Install
|
89
|
+
```bash
|
90
|
+
bundle-patch --skip-bundle-install
|
91
|
+
```
|
92
|
+
This will update the Gemfile but skip running `bundle install`.
|
62
93
|
|
94
|
+
### Major Version Updates
|
63
95
|
```bash
|
64
|
-
|
65
|
-
group :development do
|
66
|
-
gem 'bundle-patch'
|
67
|
-
end
|
96
|
+
bundle-patch --mode=all
|
68
97
|
```
|
98
|
+
This will allow updates to any version that fixes the vulnerability.
|
69
99
|
|
70
|
-
|
100
|
+
---
|
71
101
|
|
72
|
-
|
73
|
-
|
74
|
-
|
102
|
+
## βοΈ Options
|
103
|
+
|
104
|
+
| Option | Description | Default |
|
105
|
+
| ----------------------- | ------------------------------------------------------------------------- | ------- |
|
106
|
+
| `--mode=patch` | Only allow patch-level updates (e.g., 1.0.0 β 1.0.1) | β |
|
107
|
+
| `--mode=minor` | Allow minor version updates (e.g., 1.0.0 β 1.1.0) | |
|
108
|
+
| `--mode=all` | Allow all updates including major versions (e.g., 1.0.0 β 2.0.0) | |
|
109
|
+
| `--dry-run` | Only print what would be changed, don't touch the Gemfile or install gems | false |
|
110
|
+
| `--skip-bundle-install` | Modify the Gemfile, but skip `bundle install` | false |
|
111
|
+
|
112
|
+
---
|
75
113
|
|
76
114
|
## π§Ό How it works
|
77
115
|
|
78
116
|
1. Runs `bundle audit check --format json`
|
79
117
|
2. Groups advisories by gem
|
80
118
|
3. Determines the best patchable version for each gem based on `--mode`
|
81
|
-
4.
|
82
|
-
5.
|
119
|
+
4. Creates a backup of your Gemfile (Gemfile.bak)
|
120
|
+
5. Ensures the gem is either updated or explicitly added to the `Gemfile`
|
121
|
+
6. Optionally runs `bundle install` (unless `--skip-bundle-install` or `--dry-run` is used)
|
122
|
+
|
123
|
+
---
|
124
|
+
|
125
|
+
## π Troubleshooting
|
126
|
+
|
127
|
+
### Bundle Install Fails
|
128
|
+
If `bundle install` fails after updating:
|
129
|
+
1. Check the error message
|
130
|
+
2. You can revert to the backup: `cp Gemfile.bak Gemfile`
|
131
|
+
3. Try running `bundle install` manually to see more detailed errors
|
132
|
+
|
133
|
+
### Gem Can't Be Patched
|
134
|
+
If a gem can't be patched in your chosen mode:
|
135
|
+
1. Try running with `--mode=all` to see all possible updates
|
136
|
+
2. Check if there are any version conflicts in your Gemfile
|
137
|
+
3. Consider manually updating the gem to a specific version
|
138
|
+
|
139
|
+
### Security Considerations
|
140
|
+
- Always review the changes made to your Gemfile
|
141
|
+
- Test your application after applying updates
|
142
|
+
- Consider running your test suite after updates
|
143
|
+
- Check the changelog of updated gems for breaking changes
|
144
|
+
|
145
|
+
---
|
146
|
+
|
147
|
+
## π€ Contributing
|
148
|
+
|
149
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/bundle-patch.
|
150
|
+
|
151
|
+
---
|
152
|
+
|
153
|
+
## π License
|
154
|
+
|
155
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/bundle/patch/version.rb
CHANGED
data/lib/bundle/patch.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative "patch/version"
|
5
|
-
require_relative "patch/bundler_audit_installer"
|
6
5
|
require_relative "patch/audit/parser"
|
7
6
|
require_relative "patch/gemfile_editor"
|
8
7
|
require_relative "patch/gemfile_updater"
|
@@ -11,7 +10,6 @@ require_relative "patch/config"
|
|
11
10
|
module Bundle
|
12
11
|
module Patch
|
13
12
|
def self.start(config = Config.new)
|
14
|
-
BundlerAuditInstaller.ensure_installed!
|
15
13
|
advisories = Audit::Parser.run
|
16
14
|
|
17
15
|
if advisories.empty?
|
@@ -23,34 +21,16 @@ module Bundle
|
|
23
21
|
patchable = []
|
24
22
|
|
25
23
|
advisories.group_by { |adv| adv.to_h.dig("gem", "name") }.each do |name, gem_advisories|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# Collect all requirements from advisories
|
30
|
-
all_requirements = gem_advisories.flat_map do |adv|
|
31
|
-
adv.to_h.dig("advisory", "patched_versions").map do |req|
|
32
|
-
Gem::Requirement.new(req) rescue nil
|
33
|
-
end
|
34
|
-
end.compact
|
35
|
-
|
36
|
-
# Find versions that satisfy all requirements
|
37
|
-
candidate_versions = all_requirements
|
38
|
-
.map { |req| best_version_matching(req) }
|
39
|
-
.compact
|
40
|
-
.uniq
|
41
|
-
.select { |v| config.allow_update?(current_version, v) }
|
42
|
-
.sort
|
43
|
-
|
44
|
-
if candidate_versions.any?
|
45
|
-
best_patch = candidate_versions.first
|
24
|
+
result = process_gem_advisories(name, gem_advisories, config)
|
25
|
+
|
26
|
+
if result
|
46
27
|
title_list = gem_advisories.map { |a| a.to_h.dig("advisory", "title") }.uniq
|
47
|
-
puts "- #{name} (#{
|
28
|
+
puts "- #{name} (#{gem_advisories.first.to_h.dig("gem", "version")}):"
|
48
29
|
title_list.each { |t| puts " β’ #{t}" }
|
49
|
-
puts " β
Patchable β #{
|
50
|
-
|
51
|
-
patchable << { "name" => name, "required_version" => best_patch.to_s }
|
30
|
+
puts " β
Patchable β #{result[:required_version]}"
|
31
|
+
patchable << { "name" => name, "required_version" => result[:required_version] }
|
52
32
|
else
|
53
|
-
puts "- #{name} (#{
|
33
|
+
puts "- #{name} (#{gem_advisories.first.to_h.dig("gem", "version")}):"
|
54
34
|
gem_advisories.each do |adv|
|
55
35
|
puts " β’ #{adv.to_h.dig("advisory", "title")}"
|
56
36
|
end
|
@@ -79,9 +59,49 @@ module Bundle
|
|
79
59
|
end
|
80
60
|
end
|
81
61
|
|
82
|
-
def self.
|
83
|
-
|
84
|
-
|
62
|
+
def self.process_gem_advisories(name, advisories, config)
|
63
|
+
current = advisories.first.to_h.dig("gem", "version")
|
64
|
+
current_version = Gem::Version.new(current)
|
65
|
+
|
66
|
+
# Collect all requirements from advisories
|
67
|
+
all_requirements = advisories.flat_map do |adv|
|
68
|
+
adv.to_h.dig("advisory", "patched_versions").map do |req|
|
69
|
+
Gem::Requirement.new(req) rescue nil
|
70
|
+
end
|
71
|
+
end.compact
|
72
|
+
|
73
|
+
# Find versions that satisfy all requirements
|
74
|
+
candidate_versions = all_requirements
|
75
|
+
.flat_map { |req| versions_satisfying(req) }
|
76
|
+
.compact
|
77
|
+
.uniq
|
78
|
+
.select { |v| config.allow_update?(current_version, v) }
|
79
|
+
.sort
|
80
|
+
|
81
|
+
if candidate_versions.any?
|
82
|
+
{
|
83
|
+
name: name,
|
84
|
+
required_version: candidate_versions.last.to_s
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.versions_satisfying(req)
|
90
|
+
# Get all versions that satisfy the requirement
|
91
|
+
req.requirements.map do |op, version|
|
92
|
+
case op
|
93
|
+
when ">="
|
94
|
+
# For >= requirements, we need to find all versions >= this version
|
95
|
+
# We'll approximate by using the version itself
|
96
|
+
version
|
97
|
+
when "~>"
|
98
|
+
# For ~> requirements, we need to find all versions in the range
|
99
|
+
# We'll approximate by using the upper bound
|
100
|
+
version
|
101
|
+
else
|
102
|
+
version
|
103
|
+
end
|
104
|
+
end.compact
|
85
105
|
end
|
86
106
|
end
|
87
107
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bundle-patch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rishijain
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-18 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bundler-audit
|
@@ -23,6 +23,20 @@ dependencies:
|
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0.9'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: minitest
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
26
40
|
description: bundle-patch is a CLI tool that detects vulnerable gems in your Gemfile
|
27
41
|
and automatically upgrades them to a patchable version based on your configured
|
28
42
|
strategy (patch/minor/all). Uses bundler-audit under the hood.
|
@@ -44,7 +58,6 @@ files:
|
|
44
58
|
- lib/bundle/patch.rb
|
45
59
|
- lib/bundle/patch/audit/advisory.rb
|
46
60
|
- lib/bundle/patch/audit/parser.rb
|
47
|
-
- lib/bundle/patch/bundler_audit_installer.rb
|
48
61
|
- lib/bundle/patch/config.rb
|
49
62
|
- lib/bundle/patch/gemfile_editor.rb
|
50
63
|
- lib/bundle/patch/gemfile_updater.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Bundle
|
2
|
-
module Patch
|
3
|
-
class BundlerAuditInstaller
|
4
|
-
def self.ensure_installed!
|
5
|
-
return if system("bundle-audit --version > /dev/null 2>&1")
|
6
|
-
|
7
|
-
puts "π bundler-audit not found. Installing..."
|
8
|
-
success = system("gem install bundler-audit")
|
9
|
-
|
10
|
-
unless success
|
11
|
-
abort "β Failed to install bundler-audit. Please check your RubyGems setup."
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|