bundler-resolutions 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +93 -0
- data/lib/bundler/resolutions/version.rb +9 -0
- data/lib/bundler/resolutions.rb +47 -0
- data/plugins.rb +3 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5a9bc7c0b4191b262edcc52111b78fb8c67b74b0c9642ddec0036142d46c2989
|
4
|
+
data.tar.gz: bb5c955b6db7a14e56e8d5048c98709a36f634f25364a14cbe22d6606d3faeab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2d0f016d3a21dd98fe3d175d015fd4e526a514f32acf8283205db330ac9e52df4444e59a12e761882580790c8bccc1599739d3375291f598b810b4e7800b0705
|
7
|
+
data.tar.gz: cf1c8bee485fa053ec3de1ac094638381d9153796de7e77f5add4ee31953f41889f3563f6413830a5351633cb2f7960d5557447f66d52aca69ac175293696646
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
bundler-resolutions
|
2
|
+
===================
|
3
|
+
|
4
|
+
[![Gem Version](https://img.shields.io/gem/v/bundler-resolutions?color=green)](https://rubygems.org/gems/bundler-resolutions)
|
5
|
+
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
6
|
+
|
7
|
+
[bundler-resolutions](https://github.com/hlascelles/bundler-resolutions) is a [bundler](https://bundler.io/)
|
8
|
+
plugin that allows you to specify gem version requirements in your `Gemfile` without explicitly declaring
|
9
|
+
a concrete dependency on those gems. It acts much like the
|
10
|
+
[resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) feature in
|
11
|
+
[Yarn](https://yarnpkg.com/).
|
12
|
+
|
13
|
+
> [!WARNING]
|
14
|
+
> This is an experimental project and neither its API stability nor correctness should be assumed
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Add `bundler-resolutions` to your Gemfile, and add a `resolutions` group to specify the gems you
|
19
|
+
want to specify versions requirements for.
|
20
|
+
|
21
|
+
The resulting `Gemfile.lock` in this example will have nokogiri locked to `1.16.5` or above.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
plugin 'bundler-resolutions'
|
25
|
+
|
26
|
+
gem "rails"
|
27
|
+
|
28
|
+
group :resolutions do
|
29
|
+
gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
However the `Gemfile.lock` from this example will not have nokogiri at all, as it is neither
|
34
|
+
explicitly declared, nor brought in as a transitive dependency.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
plugin 'bundler-resolutions'
|
38
|
+
|
39
|
+
group :resolutions do
|
40
|
+
gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
## Detail
|
45
|
+
|
46
|
+
`bundler-resolutions` allows you to specify version requirements using standard gem syntax in your
|
47
|
+
Gemfile to indicate that you have version requirements for those gems *if* they were to be brought
|
48
|
+
in as transitive dependencies, but that you don't depend on them yourself directly.
|
49
|
+
|
50
|
+
An example use case is in the Gemfile given below. Here we are saying that although we do not use nokogiri
|
51
|
+
specifically ourselves, we want to ensure that if it is pulled in by other gems then it will
|
52
|
+
always be above the know version with a CVE.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
source "https://rubygems.org"
|
56
|
+
|
57
|
+
plugin 'bundler-resolutions'
|
58
|
+
|
59
|
+
gem "rails"
|
60
|
+
|
61
|
+
group :resolutions do
|
62
|
+
gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
The big difference between doing this and just declaring it in your Gemfile is that it will only
|
67
|
+
be used in resolutions (and be written to your lock file) if the gems you do directly depend on
|
68
|
+
continue to use it. If they stop using it, then your resolutions will take no part in the
|
69
|
+
bundler lock resolution.
|
70
|
+
|
71
|
+
The other difference is that even if it does take part in the resolutions, it will not be
|
72
|
+
present in the `DEPENDENCIES` section of the lock file, as it is not a direct dependency.
|
73
|
+
|
74
|
+
## Use cases
|
75
|
+
|
76
|
+
There are a number of reasons you may want to prevent the usage of some gem versions, without
|
77
|
+
direct use, such as:
|
78
|
+
|
79
|
+
1. You have learnt of a CVE of a gem.
|
80
|
+
2. You have internal processes that mandate the usage of certain gem versions for legal or sign off reasons.
|
81
|
+
3. You know of gem incompatibilities in later versions.
|
82
|
+
4. You know that different OS architectures do not work with some versions.
|
83
|
+
|
84
|
+
## How it works
|
85
|
+
|
86
|
+
`bundler-resolutions` works by patching the Gemfile DSL to allow for special processing
|
87
|
+
of the `resolutions` group. It also patches the bundler `filtered_versions_for` method to
|
88
|
+
allow for the resolution restrictions from the versions specified in the `resolutions` group.
|
89
|
+
|
90
|
+
This is a very early version, and it should be considered experimental.
|
91
|
+
|
92
|
+
Future work may include relating this to bundler-audit, and other security tools, so you
|
93
|
+
will automatically gain version restrictions against known CVEs.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class Resolutions
|
5
|
+
GROUP_NAME = :resolutions
|
6
|
+
|
7
|
+
attr_reader :resolutions
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@resolutions = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# This method is called by the DSL to set the resolution for a given gem. It is effectively
|
14
|
+
# an override of the normal gem method.
|
15
|
+
def gem(name, requirements)
|
16
|
+
resolutions[name.to_sym] = requirements
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def instance = @instance ||= new
|
21
|
+
end
|
22
|
+
|
23
|
+
# A module we prepend to Bundler::Resolutions::Resolver
|
24
|
+
module Resolver
|
25
|
+
# This overrides the default behaviour of the resolver to filter out versions that don't
|
26
|
+
# satisfy the requirements specified in RESOLVER_RESOLUTIONS.
|
27
|
+
def filtered_versions_for(package)
|
28
|
+
super.select do |pkg|
|
29
|
+
req = Bundler::Resolutions.instance.resolutions[package.name.to_sym]
|
30
|
+
req ? Gem::Requirement.new(*req.split(",")).satisfied_by?(pkg.version) : true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# A module we prepend to Bundler::Dsl
|
36
|
+
module Dsl
|
37
|
+
# Here we override the normal group function to capture the resolutions, and ensure any
|
38
|
+
# gem calls are effectively a no-op as regards to adding them to dependencies.
|
39
|
+
def group(*args, &blk)
|
40
|
+
args.first == GROUP_NAME ? Bundler::Resolutions.instance.instance_eval(&blk) : super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Bundler::Resolver.prepend(Bundler::Resolutions::Resolver)
|
47
|
+
Bundler::Dsl.prepend(Bundler::Resolutions::Dsl)
|
data/plugins.rb
ADDED
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bundler-resolutions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Harry Lascelles
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-02 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A bundler plugin to enforce resolutions without specifying a concrete
|
14
|
+
dependency
|
15
|
+
email:
|
16
|
+
- harry@harrylascelles.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- README.md
|
22
|
+
- lib/bundler/resolutions.rb
|
23
|
+
- lib/bundler/resolutions/version.rb
|
24
|
+
- plugins.rb
|
25
|
+
homepage: https://github.com/hlascelles/bundler-resolutions
|
26
|
+
licenses:
|
27
|
+
- MIT
|
28
|
+
metadata:
|
29
|
+
homepage_uri: https://github.com/hlascelles/bundler-resolutions
|
30
|
+
documentation_uri: https://github.com/hlascelles/bundler-resolutions
|
31
|
+
changelog_uri: https://github.com/hlascelles/bundler-resolutions/blob/master/CHANGELOG.md
|
32
|
+
source_code_uri: https://github.com/hlascelles/bundler-resolutions/
|
33
|
+
bug_tracker_uri: https://github.com/hlascelles/bundler-resolutions/issues
|
34
|
+
rubygems_mfa_required: 'true'
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubygems_version: 3.5.11
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: A bundler plugin to enforce resolutions without specifying a concrete dependency
|
54
|
+
test_files: []
|